Sortuj miesiące roku


19

Napisz funkcję lub program, który trwa wejściowych ciągów, w pełni orkisz, nazw angielskich miesiąc w przypadku tytułowej: January, February, March, itd. (Null / CR / LF zakończone OK, ograniczony z jakimś charakterze non-alfa, jeśli tak zdecydujesz) i albo

  • porównuje dwa dane wejściowe, zwracając wartość Prawdy, jeśli drugie dane wejściowe są większe (w kolejności miesiąca) niż pierwsze. Równe wartości dają wartość Falsey

  • lub sortuje dowolną ich sekwencję (listę, łańcuch rozdzielany itp.) w kolejności chronologicznej

(Istota wyzwania polega na zdefiniowaniu metody / wyrażenia, które daje prawidłowy sort leksykograficzny. Niektóre języki mogą mieć krótszą odpowiedź na jedno lub drugie)

Nie można używać żadnych wewnętrznych metod analizy czasu (np. strptime), Aby tłumaczyć nazwę miesiąca na liczbę lub wstępnie mapowane nazwy miesięcy. Używaj właściwości samych ciągów, zdefiniowanej przez ciebie oszczędnej tabeli przeglądowej lub czegoś sprytnego.

Przykład

Przykłady działania, choć pierwszy jest zabroniony przez reguły ...

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') 

Poniższe wersje są jednak OK, ponieważ kodujemy te informacje

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]

Lub możesz wykonać funkcję sortowania

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]) 

Przykładowe testy

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')

Nie można użyć żadnych wewnętrznych metod analizy czasu (np. Strptime), aby przetłumaczyć nazwę miesiąca na liczbę. To jest trochę niejasne. Czy możemy użyć predefiniowanego języka, który zawiera nazwy miesięcy?
Luis Mendo,

Skasuję wtedy moją odpowiedź. Ale nadal nie jest jasne, co jest dozwolone, a co nie.
Luis Mendo,

Problem polega na tym, że nie można przewidzieć wszystkich potencjalnych sztuczek, takich jak predefiniowane tablice. Być może lepszym rozwiązaniem byłoby użycie mniej powszechnego zestawu ciągów, takich jak wymyślone nazwy. Ale chyba jest już za późno
Luis Mendo,

Czy to, co wyrażam, jest jasne? Jeśli Python miał wbudowaną monthslistę, która była listą wszystkich nazw miesięcy, chciałbym zabronić months[x] < months[y]jako odpowiedzi. Lista nazw miesięcy ma kilka bardziej specyficznych cech (różna długość, wspólność), które sprawiają, że wyzwanie jest łatwiejsze / trudniejsze niż losowo generowane ciągi znaków.
Nick T

Tak, myślę, że to jasne. Obawiam się, że mogą istnieć inne podobne przypadki, których nie wykluczyłeś (ale nie wiem, które)
Luis Mendo,

Odpowiedzi:


41

Galaretka , 19 bajtów

11ị“bMAanlseovc”iµÞ

Jest to monadyczny link, który przyjmuje listę jako argument i sortuje ją. Wypróbuj online!

tło

Galaretka wykorzystuje modułowe indeksowanie 1. Jeśli powtarzamy nazwy miesięcy wystarczająco często, aby uzyskać 11 znaków, otrzymujemy następującą tablicę.

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

W 11 -tego (ostatniego) kolumny, wszystkie znaki są różne, więc możemy z nich korzystać w celu identyfikacji kolejność miesięcy.

Jak to działa

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
Ciekawe, jak oceniasz miesiąc w rankingu „bMAanlseovc”? Indeks dopasowania pierwszego znaku?
ljeabmreosn

Dodałem wyjaśnienie.
Dennis

8
Wow, to naprawdę sprytne!
ljeabmreosn

15

kod maszynowy x86, 26 25 bajtów

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

Kod zestawu:

    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;

Następująca funkcja skrótu powoduje ustawienie nazw miesięcy we właściwej kolejności (znalezionej przez brutalną siłę):

(x ^ 0xc0) * 0x01435f30

Jest stosowany do pierwszych 4 bajtów (32 bity) ciągu wejściowego, ułożonych w kolejności little-endian. Następnie porównując wynik i używając SALCdo ustawienia rejestru wyników (al):

  • -1 (prawda), jeśli miesiące są w porządku
  • 0 (fałsz), jeśli drugi miesiąc poprzedza pierwszy miesiąc (lub są takie same)

4
Jestem pod wrażeniem. Bardzo krótki fragment kodu bez użycia języka specyficznego dla golfa.
ShuberFu,

13

Galaretka , 15 bajtów

Oḅ32 354*%991µÞ

Brak linku tłumacza online, ponieważ jest to jedno wolne przesyłanie. Program używa funkcji skrótu 354^(input interpreted as base 32 int) % 991jako klawisza sortowania, który daje wyniki w odpowiedniej kolejności. Program nie zakończy się w najbliższym czasie, ponieważ wyniki potęgowania są gigantyczne - dla „września” należy obliczyć liczbę z 0,24 biliardowymi cyframi!

Objaśnienie galaretki:

              Þ         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

Skrypt proof of concept w języku Python - zwróć uwagę na użycie powmodułowego potęgowania, które jest znacznie wydajniejsze:

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
„Brak linku do tłumacza online, ponieważ jest to jedno wolne przesyłanie”. W takim przypadku możesz równie dobrze posortować miesiące ręcznie. ;-)
owacoder

Może mógłbyś PR poprosić o funkcję, aby zoptymalizować pow / mod ...
Nick T

@NickT To świetny pomysł, ale niestety sposób konfiguracji interpretera (z każdym operatorem zdefiniowanym osobno) może być nieco trudny. I Jelly nie działa dobrze z operatorami, które mają więcej niż dwa argumenty, więc zdefiniowanie oddzielnego operatora nie zadziałałoby albo ...
Sp3000,

Nie jest to oddzielny operator ani nic, tylko głębsza introspekcja, aby sprawdzić, czy po operacji zasilania następuje podział modułowy. Brzmi łatwo? : P
Nick T

5

Python, 64 61 57 bajtów

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

Sonda lambda pobiera dwa miesiące i porównuje je. Przetestuj na Ideone .

Dzięki @ljeabmreosn za grę w golfa na 3 bajtach i torowanie drogi dla kolejnych 3!


2
Wreszcie ujawniasz tajemnicę czarnej magii, której użyłeś do szybkiego obliczenia prawidłowego miesiąca w swojej odpowiedzi na galaretkę!
Wartość tuszu

1
Czy przejście s[10%len(s)]do (4*s)[10]pracy?
ljeabmreosn

1
@ljeabmreosn To naprawdę działa. Dzięki!
Dennis

1
Nie widziałem jeszcze domyślnego argumentu <strike> ab </strike> w lambda: P
Nick T

4

Python, 81 71 bajtów

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

https://repl.it/CluN/1

Porównuje indeks mdrugiej i trzeciej litery dwóch miesięcy.

Wersja 83-bajtowa do sortowania listy miesięcy:

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

3

Rubinowy, 58 bajtów

Wykorzystuje sztuczkę sortującą według miesiąca z odpowiedzi @ atlasologist .

->a{a.sort_by{|i|"anebarprayunulugepctovec".index i[1,2]}}

Funkcja porównania jest nieco dłuższa i ma 63 bajty

->a,b{m=->i{"anebarprayunulugepctovec".index i[1,2]};m[a]<m[b]}

3

J, 66 65 bajtów

Wykorzystuje fakt, że f (m) = 2 * (ord (m [0]) + ord (m [-1])) // len (m) jest prawidłową funkcją w ograniczonej dziedzinie 12 miesięcy:

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

Stosowanie:

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

(W żadnym wypadku nie jest to najlepszy pomysł, ale nie chciałem kraść niczyjej sztuczki rankingowej!)

Oto krótsza wersja z wykorzystaniem metody @ atlasologist :

J, 63 bajty

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

Stosowanie:

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

I znacznie krótsza wersja wykorzystująca sprytną metodę @ Dennisa :

J, 34 bajty

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

3

Haskell, 74 bajty

Mój pierwszy golf golfowy, tak! Ogólna idea tego jest zainspirowana najwyższą odpowiedzią w Galaretce oraz faktem, że gdy nazwy miesięcy są cykliczne, jedenasta postać jest zawsze wyjątkowa.

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

Oto wersja bez golfa, aby zobaczyć, jak to działa:

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)

eFunkcja odpowiada funkcji eleventhChar (niestety nie odpędzić 4 bajty w związku z ograniczeniem monomorfizm chyba) i #odpowiada funkcji infiks do inOrderfunkcji.

Ładne, małe rozwiązanie, ale mogą istnieć sposoby na zmniejszenie liczby bajtów (znalazłem kilka podczas pisania tego!)


Można skrócić e s=head.drop 10$cycle sjak to zrobiłeś w swoim wyjaśnieniem stosując .zamiast $: e=head.drop 10.cycle. Jednak użycie operatora indeksu listy !!jest jeszcze krótsze:e=(!!10).cycle
Laikoni

Świetne sugestie. Czasami po prostu przeoczysz te rzeczy. Wielkie dzięki. Wkrótce go edytuję.
altana

2

Java, 133 123

Gra w golfa:

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

Szukałem sprytnej techniki, takiej jak w odpowiedzi asemblera, ale jej znalezienie zajęło mi zbyt wiele czasu, więc wybrałem tę samą technikę, której używali wszyscy inni.

Nie golfowany:

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

}

Możesz użyć substringzamiast tego, jeślicharAt
anatolyg

@anatolyg dzięki, nie jestem pewien, jak ten mi uciekł. Mogłem również usunąć, "" +ponieważ nie ma już surowych charplików.

2

Język maszynowy ARM w systemie Linux 44 40 bajtów

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

Kiedyś inną funkcję skrótu niż anatolyg „s rozwiązania i próbował instrukcji użycie kciuka, aby zaoszczędzić kilka bajtów (choć wiał 8 bajtów wejściu w tryb kciuka).

Możesz to wypróbować na Raspberry Pi lub urządzeniu z Androidem z 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]);}

Aby uruchomić, wpisz coś takiego

$ ./foo January February; echo $?

Obecna wersja poprawnie obsługuje teraz przypadek równości (i inne).


Myślę, że nie potrzebujesz kodu, który jawnie przechodzi w tryb Thumb. Z tego co pamiętam, musisz tylko powiedzieć linkerowi, że twoja procedura jest w trybie kciuka, a linker ustawi LSB w adresie twojej procedury na 1, więc procesor automatycznie przełączy się w tryb Thumb po wywołaniu twojego kodu.
anatolyg

Co też bfacrobi?
anatolyg

@anatolyg ite gewarunkowo wykonuje następną instrukcję ( movge r0, #0), jeśli r3 >= r0w przeciwnym razie następująca instrukcja jest wykonywana ( movlt r0, #1). Myślę, że jest tu miejsce na zrzucenie kilku bajtów, ale nie miałem czasu nad tym
popracować

1

Perl 6 , 55 bajtów

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

Wymagałoby to jeszcze kilku bajtów dla wersji porównawczych:

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

Test:

#! /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 znaków

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

Wykorzystuje fakt, że nazwa każdego miesiąca jest unikalna pod względem pierwszego i czwartego znaku (lub trzeciego w maju), aby zdefiniować typ danych, który może być automatycznie analizowany i porównywany według języka. Funkcja „r” konwertuje ciąg, chwytając pierwsze cztery znaki (lub mniej), a następnie wybierając pierwszy i ostatni. Zatem „a # b” jest operatorem porównującym wartości:

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

Prawdopodobnie można to zrobić w bardziej wydajny sposób, ale chciałem to zrobić przy użyciu użytecznego typu danych reprezentującego miesiące.


1

PowerShell, 96 88 63 bajtów

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

na przykład

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

Teraz robi drugie wyzwanie sortowania listy w kolejności; poprzednie wersje przeprowadziły porównanie testu dwumiesięcznego:

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

Na podstawie dwóch drugich znaków w nazwie miesiąca.



0

JavaScript, 118 bajtów

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` `}

Można by grać w golfa więcej, prawdopodobnie pozbywając się ci używając array.map, ale to jest to, co na razie mam ...


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

0

Bash, 101 bajtów

jest to funkcja taka jak 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}));}

test

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

0

k4, 29

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

Port odpowiedzi na galaretkę @ Dennisa .

To jest sortownik, a nie komparator; co ciekawe, komparator jest w prosty sposób implementowany przez ten sam algorytm i tylko o jeden bajt dłużej:

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

0

Bash + coreutils, 94 bajty 93 bajty

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

Jest to próba wymyślenia transformacji, która sortuje leksykograficznie. Jeśli przyjrzysz się uważnie kluczowi transformacji FMAyulgSOND, zobaczysz miesiące od lutego do grudnia (styczeń staje się pusty po transformacji; jest on ciągnięty do góry za pomocą „B” jako separatora). Odwracanie, obcinanie i usuwanie niekluczowych liter umożliwia wyciągnięcie tej sztuczki.

90 bajtów przy użyciu ustawień regionalnych C.

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

... gdzie ␉ jest znakiem tabulacji.

80 bajtów przy użyciu ustawień regionalnych C.

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

... przy użyciu metody @ atlasolog. Jest to sposób na wykorzystanie tego podejścia do pracy z większą liczbą lokalizacji.

Test / użycie

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

wyjścia:

January
February
March
April
May
June
July
August
September
October
November
December
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.