Сортуйте місяці року


19

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

  • порівнює два входи, повертаючи значення Truthy, якщо другий вхід більший (у місячному порядку), ніж перший. Рівні значення призводять до значення Фальсі

  • або сортує довільну послідовність (список, обмежений рядок тощо) у хронологічному порядку

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

Ви не можете використовувати будь-які внутрішні методи аналізу часу (наприклад 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µÞ

Це монадичне посилання, яке приймає список як аргумент і сортує його. Спробуйте в Інтернеті!

Фон

Jelly використовує модульну індексацію на основі 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 (помилково), якщо другий місяць передує першому місяцю (або вони однакові)

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 ...
Nick T

@NickT Це відмінна ідея, але, на жаль, спосіб налаштування перекладача (з кожним оператором визначено окремо), це може бути дещо хитро. І Jelly не дуже добре працює з операторами, у яких є більше двох аргументів, тому визначення окремого оператора теж не спрацює ...
Sp3000

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

5

Пітон, 64 61 57 байт

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

Лямбда займає два місяці як вхід і порівнює їх. Перевірте це на Ideone .

Дякуємо @ljeabmreosn за те, що ти граєш на 3 байти та прокладаєш дорогу ще на 3!


2
Нарешті, ви розкриєте секрет чорної магії, за допомогою якої швидко обчислили правильний місяць у своїй відповіді «Желе»!
Значення чорнила

1
Чи змінилася s[10%len(s)]б (4*s)[10]робота?
ljeabmreosn

1
@ljeabmreosn Це справді працює. Спасибі!
Денніс

1
Ще не бачив <strike> ab </strike> використання аргументів за замовчуванням у лямбда: P
Nick T

4

Пітон, 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 :

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

Гольф:

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

Я шукав розумну техніку, як у відповіді асемблера, але це зайняло занадто багато часу, щоб зрозуміти, тому я пішов з тією ж технікою, що і всі інші.

Безголівки:

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замість цього використати ifcharAt
anatolyg

@anatolyg дякую, я не впевнений, як той мене врятував. Мені також вдалося видалити, "" +оскільки вже немає сировини char.

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

Я використовував іншу хеш-функцію, ніж анатоліг «s рішення і спробував інструкції використовувати великий палець , щоб заощадити кілька байт (хоча я підірвав 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 $?

Поточна версія тепер правильно обробляє випадок рівності (та інші).


Я думаю, вам не потрібен код, який явно переходить у режим великого пальця. З того, що я пам’ятаю, вам потрібно лише повідомити лінкеру, що ваша процедура перебуває в режимі великого пальця, і лінкер встановить LSB в адресі вашої процедури на 1, тому процесор автоматично перейде в режим великого пальця, коли буде викликаний ваш код.
anatolyg

Також, що робить bfac?
anatolyg

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

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

Haskell, 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

k4, 29

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

Порт @ Dennis's Jelly .

Це сортувальник, а не компаратор; що цікаво, компаратор тривіально реалізований за тим самим алгоритмом, і лише на один байт довше:

{(<)."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. Обов'язково - це спосіб використовувати такий підхід для роботи з більшою кількістю локалів.

Тест / Використання

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.