Сортировать месяцы года


19

Написать функцию или программу , которая принимает строку входы, полностью полбы, английские названия месяцев в названии случае: January, February, Marchи т.д. (нуль / CR / LF прекращено в порядке, разграничены с некоторыми не-буквенного символа , если вы этого хотите) и либо

  • сравнивает два входа, возвращая значение Truthy, если второй вход больше (в месячном порядке), чем первый. Равные значения приводят к значению Falsey

  • или сортирует произвольную последовательность (список, строку с разделителями и т. д.) в хронологическом порядке

(Суть задачи заключается в определении метода / выражения, которое дает правильный лексикографический вид. Некоторые языки могут иметь более короткий ответ с одним или другим)

Вы не можете использовать какие-либо внутренние методы анализа времени (например strptime), чтобы перевести название месяца в число или предварительно сопоставленное отображение названий месяцев. Используйте свойства самих строк, экономной справочной таблицы, которую вы определяете, или что-то умное.

пример

Функциональные примеры, хотя первое запрещено правилами ...

import datetime
def is_later_month(a, b):
    '''
    Example of prohibited code because it relies on language 
    features about how to parse month names
    '''
    return datetime.strptime(a, '%B') < datetime.strptime(b, '%B') 

Тем не менее, все версии в порядке, потому что мы кодируем

months = {
    'January':  1, 'February':  2, 'March':      3,
    'April':    4, 'May':       5, 'June':       6,
    'July':     7, 'August':    8, 'September':  9,
    'October': 10, 'November': 11, 'December':  12,
}
def is_later_month(a, b):
    """
    Returns True/False when comparing two months.
    """
    return months[a] < months[b]

Или вы могли бы сделать функцию сортировки

months = {'as above...'}
def sort_months(l):
    """
    Sorts list and returns it. Different input and output than the above, 
    but equally valid. Sorting versus comparing might be shorter in your
    favorite language.
    """
    return sorted(l, key=lambda x: months[x]) 

Пример тестов

assert is_later_month('January', 'February')
assert is_later_month('January', 'December')
assert is_later_month('November', 'December')
assert not is_later_month('July', 'July')
assert not is_later_month('October', 'September')

Вы не можете использовать какие-либо внутренние методы анализа времени (например, strptime), чтобы перевести название месяца в число. Это немного неясно. Можем ли мы использовать предопределенный литерал языка, который содержит названия месяцев?
Луис Мендо

Я удалю свой ответ тогда. Но до сих пор не ясно, что разрешено, а что нет.
Луис Мендо

Проблема в том, что вы не можете предвидеть все эти потенциальные уловки, такие как предопределенные массивы. Возможно, лучшим вариантом было бы использование менее распространенного набора строк, таких как выдуманные имена. Но сейчас уже слишком поздно для этого, я думаю
Луис Мендо

Что я выражаю ясно? Если бы в Python был встроенный monthsсписок всех названий месяцев, я бы запретил months[x] < months[y]в качестве ответа. Список названий месяцев имеет некоторые более специфические особенности (разная длина, общность), которые упрощают / усложняют задачу по случайно сгенерированным строкам.
Ник Т

Да, я думаю, это понятно. Я просто боюсь, что могут быть другие подобные случаи, которые вы явно не исключили (но я не знаю, какие из них)
Луис Мендо

Ответы:


41

Желе , 19 байт

11ị“bMAanlseovc”iµÞ

Это монадическая ссылка, которая принимает список в качестве аргумента и сортирует его. Попробуйте онлайн!

Фон

Желе использует модульную индексацию на основе 1. Если мы повторяем названия месяцев достаточно часто, чтобы получить 11 символов, мы получаем следующий массив.

J a n u a r y J a n u
F e b r u a r y F e b
M a r c h M a r c h M
A p r i l A p r i l A
M a y M a y M a y M a
J u n e J u n e J u n
J u l y J u l y J u l
A u g u s t A u g u s
S e p t e m b e r S e
O c t o b e r O c t o
N o v e m b e r N o v
D e c e m b e r D e c

В 11- м (последнем) столбце все символы разные, поэтому мы можем использовать их для определения порядка месяцев.

Как это устроено

11ị“bMAanlseovc”iµÞ  Monadic link. Argument: A (array of months)

                 µ   Combine the preceding chain into a link.
                  Þ  Sort A by that link.
11ị                    Select the 11th character of the month's name.
   “bMAanlseovc”       Find the index of that character in "bMAanlseovc".
                       For 'u' ("January"), this returns 0 (not found).

1
Просто любопытно, как вы оцениваете месяц с "bMAanlseovc"? Индекс соответствия первого символа?
ljeabmreosn

Я добавил объяснение.
Деннис

8
Вау, это действительно умно!
ljeabmreosn

15

машинный код x86, 26 25 байт

HexDump:

ff 32 8b 01 34 c0 68 30 5f 43 01 59 f7 e1 91 5a
80 f2 c0 f7 e2 3b c8 d6 c3

Код сборки:

    push dword ptr [edx];
    mov eax, [ecx];
    xor al, 0xc0;
    push 0x01435f30;
    pop ecx;
    mul ecx;
    xchg eax, ecx;
    pop edx;
    xor dl, 0xc0;
    mul edx;
    cmp ecx, eax;
    _emit 0xd6;
    ret;

Следующая хеш-функция помещает названия месяцев в правильном порядке (определяется методом грубой силы):

(x ^ 0xc0) * 0x01435f30

Он применяется к первым 4 байтам (32 битам) входной строки, расположенным в порядке с прямым порядком байтов. Затем сравниваем результат и используем SALCдля установки регистр результата (al):

  • -1 (верно), если месяцы в порядке
  • 0 (false), если второй месяц предшествует первому месяцу (или они совпадают)

4
Я впечатлен. Очень короткий фрагмент кода без использования языка, специфичного для кода-гольфа.
ShuberFu

13

Желе , 15 байт

Oḅ32 354*%991µÞ

Здесь нет ссылки на переводчика онлайн, потому что это одна медленная подача. Программа использует функцию хеширования 354^(input interpreted as base 32 int) % 991в качестве ключа сортировки, которая дает выходные данные в правильном порядке. Программа не завершится в ближайшее время, потому что результаты возведения в степень огромны - для «сентября» необходимо вычислить число с 0,24 квадриллионными цифрами!

Объяснение желе:

              Þ         Sort by...
             µ          Monadic link consisting of...

O                       Convert month string to code points
 ḅ32                    Take base 32
     354*               Perform 354 to the power of the result
         %991           Take modulo 991

Python подтверждение концепции сценария - обратите внимание на использование powдля модульного возведения в степень, что гораздо более эффективно:

import random

def base_convert(string, base):
    total = 0

    for c in string:
        total = total * base + ord(c)

    return total

def month_hash(month):
    return pow(354, base_convert(month, 32), 991)

months = ["January", "February", "March", "April", "May", "June", "July",
    "August", "September", "October", "November", "December"]
random.shuffle(months)

print(months)
print(sorted(months, key=month_hash))

5
«Здесь нет ссылки на переводчика онлайн, потому что это одна медленная подача». В этом случае вы можете также отсортировать месяцы вручную. ;-)
owacoder

Может быть, вы могли бы PR запрос функции для оптимизации Pow / Mod ...
Ник Т

@NickT Это отличная идея, но, к сожалению, с тем, как настроен интерпретатор (с каждым оператором, определенным отдельно), это может быть немного сложно. И Jelly не очень хорошо работает с операторами, которые имеют более двух аргументов, поэтому определение отдельного оператора тоже не вполне
подойдет

Не отдельный оператор или что-то еще, просто какой-то более глубокий самоанализ, чтобы увидеть, следует ли за операцией питания модульное деление. Звучит легко? : P
Ник Т

5

Python, 64 61 57 байт

lambda x,y,g='bMAanlseovc'.find:g((x*4)[10])<g((y*4)[10])

Лямбда принимает два месяца в качестве входных данных и сравнивает их. Проверьте это на Ideone .

Спасибо @ljeabmreosn за то, что вы сыграли в гольф 3 байта и проложили путь еще 3!


2
Наконец, вы раскрываете секрет черной магии, которую использовали, чтобы быстро вычислить правильный месяц в своем ответе на желе!
Value Ink

1
Будет ли меняться s[10%len(s)]на (4*s)[10]работу?
ljeabmreosn

1
@ljeabmreosn Это действительно работает. Благодарность!
Деннис

1
Еще не видел, чтобы <strike> ab </ strike> использовало аргументы по умолчанию в лямбде: P
Ник T

4

Python, 81 71 байт

lambda x,y,m='anebarprayunulugepctovec':m.index(x[1:3])<m.index(y[1:3])

https://repl.it/CluN/1

Сравнивает индекс mпо вторым и третьим буквам двух месяцев.

83-байтовая версия для сортировки списка месяцев:

lambda x:sorted(x,key=lambda i:'JanFebMarAprMayJunJulAugSepOctNovDec'.index(i[:3]))


3

J 66 65 байт

Использует тот факт, что f (m) = 2 * (ord (m [0]) + ord (m [-1])) // len (m) является допустимой функцией в ограниченной области 12 месяцев:

>/@:('7/HEäWa<+0'&i.@(3 :'u:<.(#>y)%~+:+/3&u:({.>y),({:>y)')"0)"1

Использование:

   bigger =: >/@:('7/HEäWa<+0'&i.@(3 :'u:<.(#>y)%~+:+/3&u:({.>y),({:>y)')"0)"1
   bigger ('May'; 'March')
1
   bigger ('May'; 'June')
0

(Ни в коем случае это не лучшая идея, но я не хотел украсть чей-то хитрый рейтинг!)

Вот более короткая версия с использованием метода @ atlasologist :

J, 63 байта

m=:[:}.3{.]
[:>/(12 2$'anebarprayunulugepctovec')i.([:m[),:[:m]

Использование:

   bigger =: [:>/(12 2$'anebarprayunulugepctovec')i.([:m[),:[:m]
   'January' bigger 'May'
0
   'June' bigger 'May'
1

И намного более короткая версия с использованием @ Dennis's умный метод :

J, 34 байта

>&:('ubMAanlseov'&i.@:{.@:(10&|.))

3

Haskell, 74 байта

Мой первый код гольф, ура! Общая идея этого навеяна главным ответом в Jelly и тем фактом, что когда циклически повторяются названия месяцев, 11-й символ всегда уникален.

e s=head.drop 10$cycle s;a#b=elem(e b)$tail$dropWhile(/=e a)"ubMAanlseovc"

Вот незагрязненная версия, чтобы увидеть, как это работает:

order :: String
order = "ubMAanlseovc"

eleventhChar :: String -> Char
eleventhChar
  = head . drop 10 $ cycle

inOrder :: String -> String -> Bool
inOrder m1 m2
  = elem (eleventhChar m2) (tail $ dropWhile (/= eleventhChar m1) order)

eФункция представляет собой функцию eleventhChar ( к сожалению , не может сдирать 4 байта из - за ограничение мономорфизма я думаю) и #функция инфиксной соответствует inOrderфункции.

Небольшое изящное решение, но могут быть способы сброса большего количества байтов (я нашел некоторые только во время написания этого!)


Вы могли бы сократить , e s=head.drop 10$cycle sкак вы делали в вашем объяснении, используя .вместо $: e=head.drop 10.cycle. Однако использование оператора индекса списка !!еще короче:e=(!!10).cycle
Laikoni

Отличные предложения. Иногда вы просто пропускаете эти вещи. Большое спасибо. Скоро отредактирую.
беседка

2

Ява, 133 123

Golfed:

boolean f(String a,String b){return h(a)<h(b);}int h(String s){return"anebarprayunulugepctovec".indexOf(s.substring(1,3));}

Я искал умную технику, как в ответе ассемблера, но это заняло слишком много времени, чтобы понять, поэтому я выбрал ту же технику, которую использовали все остальные.

Ungolfed:

import java.util.Random;

public class SortTheMonthsOfTheYear {

  public static void main(String[] args) {
    // @formatter:off
    String[] MONTHS = new String[] {
        "January", "February", "March",
        "April",   "May",      "June",
        "July",    "August",   "September",
        "October", "November", "December"
    };
    // @formatter:on

    Random r = new Random();
    for (int i = 0; i < 100; ++i) {
      int m1 = r.nextInt(MONTHS.length);
      int m2 = r.nextInt(MONTHS.length);
      System.out.println("Input: " + MONTHS[m1] + " < " + MONTHS[m2]);
      System.out.println("Expected: " + (m1 < m2));
      System.out.println("Actual:   " + new SortTheMonthsOfTheYear().f(MONTHS[m1], MONTHS[m2]));
      System.out.println();
    }
  }

  // Begin golf
  boolean f(String a, String b) {
    return h(a) < h(b);
  }

  int h(String s) {
    return "anebarprayunulugepctovec".indexOf(s.substring(1, 3));
  }
  // End golf

}

Вы можете использовать substringвместо этого, еслиcharAt
Анатолий

@anatolyg спасибо, я не уверен, как этот сбежал от меня. Я также был в состоянии удалить, "" +так как нет больше сырых chars.

2

Машинный язык ARM в Linux 44 40 байт

e28fc001     add ip, pc, #1
e12fff1c     bx ip
6803         ldr r3, [r0, #0]
6808         ldr r0, [r1, #0]
4a05         ldr r2, [pc, #20]
f08303dd     eor.w r3, r3, #221
f08000dd     eor.w r0, r0, #221
4353         muls r3, r2
4350         muls r0, r2
4283         cmp r3, r0
bfac         ite ge
2000         movge r0, #0
2001         movlt r0, #1
4770         bx lr
2f68f24c

Я использовал хеш-функцию, отличную от решения Анатолиг и попытался использовать инструкции для большого пальца, чтобы сохранить несколько байтов (хотя я выбрал 8 байтов, переходя в режим большого пальца).

Вы можете попробовать это на устройстве Raspberry Pi или Android с GNURoot.

int main(int argc,char**argv){
return ((int(*)(char*,char*))"\
\1\xc0\x8f\xe2\
\x1c\xff\x2f\xe1\
\3\x68\x8\x68\
\5\x4a\x83\xf0\
\xdd\3\x80\xf0\
\xdd\x43\x53\x43\
\x50\x4a\x83\x42\
\xac\bf\0\x20\
\1\x20\x70\x47\
\x4c\xf2\x68\x2f\
")(argv[1],argv[2]);}

Для запуска введите что-то вроде

$ ./foo January February; echo $?

Текущая версия теперь правильно обрабатывает случай равенства (и другие).


Я думаю, что вам не нужен код, который явно переключается в режим Thumb. Из того, что я помню, вам нужно только сказать компоновщику, что ваша процедура находится в режиме большого пальца, и компоновщик установит LSB в адресе вашей процедуры в 1, поэтому процессор автоматически переключится в режим большого пальца при вызове вашего кода.
Анатолий

Кроме того, что делает bfac?
Анатолий

@anatolyg ite geусловно выполняет следующую инструкцию ( movge r0, #0), если r3 >= r0, в противном случае , выполняется следующая инструкция ( movlt r0, #1). Я думаю, что здесь есть место, чтобы сбросить пару байтов, но у меня не было времени поработать над этим :-)
terracecat

1

Perl 6 , 55 байт

*.sort({index 'anebarprayunulugepctovec',.substr(1,2)})

Для сравнительных версий потребуется еще несколько байтов:

{[<] @_».&{index 'anebarprayunulugepctovec',.substr(1,2)}}
{[<] .map: {index 'anebarprayunulugepctovec',.substr(1,2)}}

Тестовое задание:

#! /usr/bin/env perl6
use v6.c;
use Test;

my @months = <
  January February March April May June July
  August September October November December
>;

my &month-sort = *.sort({index 'anebarprayunulugepctovec',.substr(1,2)});

plan 100;

for ^100 {
  # 「.pick(*)」 returns all elements in random order
  is-deeply month-sort(@months.pick(*)), @months.List;
}

1

Хаскель, 118 персонажей

data M=Ju|Fr|Mc|Ai|My|Je|Jy|Au|St|Oo|Ne|De deriving(Ord,Eq,Read)
r=read.([head,last]<*>).lines.take 4
a#b=(r a::M)<r b

Использует тот факт, что имя каждого месяца уникально по его первым и четвертым символам (или 3-му по май) для определения типа данных, который может автоматически анализироваться и сравниваться языком. Функция 'r' преобразует строку, захватывая первые четыре символа (или меньше), а затем просто выбирая первый и последний. Тогда «a # b» является оператором для сравнения значений:

*Main> "June" # "March"
False
*Main> "June" # "July"
True
*Main> "January" # "July"
True
*Main> "January" # "November"
True
*Main> "December" # "November"
False

Возможно, это можно сделать более эффективным способом, но я хотел попробовать сделать это, используя полезный тип данных для представления месяцев.


1

PowerShell, 96 88 63 байта

$input|Sort{'anebarprayunulugepctovec'.IndexOf((-join$_[1,2]))}

например

PS C:\Code> 'February', 'January', 'December', 'April' | .\monthsort.ps1
January
February
April
December

Теперь выполняется вторая задача сортировки списка по порядку; Предыдущие версии делали сравнение двухмесячного теста:

v2.
$l,$r=$args|%{-join$_[1,2]};($d='anebarprayunulugepctovec').indexof($l)-lt$d.IndexOf($r)

v1.
$l,$r=$args|%{-join$_[1,2]};$r-match('an|eb|ar|pr|ay|un|ul|ug|ep|ct|ov|ec'-split$l)[1].Trim('|')

e.g.

PS C:\code> .\Test-MonthsInOrder.ps1 January February
True

На основе вторых двух символов в названии месяца.



0

Javascript, 118 байт

u=p=>{p=p.split` `.sort();c=[];for(i=0;i<12;i++){c.push(p["4 3 7 0 8 6 5 1 11 10 9 2".split` `[i]]);}return c.join` `}

Может быть больше в гольфе, вероятно, избавившись cи используя array.map, но это то, что у меня есть сейчас ...


for(i=0;i<12;)c.push(p[[4,3,7,0,8,6,5,1,11,10,9,2][i++]]);
pinkfloydx33

0

Баш, 101 байт

это такая функция, как is_later

f(){ s=ubMAanlseovc a=$1$1$1 b=$2$2$2 c=${a:10:1} d=${b:10:1} e=${s%$c*} f=${s%$d*};((${#e}<${#f}));}

тестовое задание

$ f January December && echo later || echo not later
not later

0

к4, 29

{x@<"ubMAanlseovc"?(*|11#)'x}

Порт @ Денниса желе ответ .

Это сортировщик, а не компаратор; Интересно, что компаратор тривиально реализуется тем же алгоритмом, и только на один байт длиннее:

{(<)."ubMAanlseovc"?(*|11#)'x}

0

Bash + coreutils, 94 байта, 93 байта

s(){ x=FMAyulgSOND;for y;{ rev<<<${y:0:3}|tr -d -C $x|tr $x C-M;echo B$y;}|sort|cut -f2 -dB;}

Это попытка придумать преобразование, которое сортирует лексикографически. Если вы внимательно посмотрите на ключ преобразованияFMAyulgSOND вы увидите месяцы с февраля по декабрь (январь становится пустым после преобразования; он вытягивается вверх, используя «B» в качестве разделителя). Реверсирование, усечение и удаление неключевых букв позволяют осуществить этот трюк.

90 байтов, используя C Locale

s(){ x=FMAyulgSOND;for y;{ rev<<<${y:0:3}|tr -d -C $x|tr $x C-M;echo \␉$y;}|sort|cut -f2;}

... где ␉ символ табуляции.

80 байтов, используя C Locale

s(){ x=anebarprayunulugepctovec;for y;{ echo ${x%${y:1:2}*}\␉$y;}|sort|cut -f2;}

... используя метод @ atlasolog. Необходимо использовать этот подход для работы с большим количеством языков.

Тест / Usage

s December November October September August July June May April March February January

выходы:

January
February
March
April
May
June
July
August
September
October
November
December
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.