Sortir bulan dalam setahun

19

Menulis fungsi atau program yang mengambil input string penuh dieja, nama-nama bulan bahasa Inggris dalam kasus judul: January, February, March, dll (null / CR / LF dihentikan OK, dibatasi dengan beberapa karakter non-alpha jika Anda memilih demikian) dan baik

  • membandingkan dua input, mengembalikan nilai Kebenaran jika input kedua lebih besar (dalam urutan bulan) dari yang pertama. Nilai yang sama menghasilkan nilai Falsey

  • atau mengurutkan urutan acak (daftar, string terbatas, dll.) dari mereka dalam urutan kronologis

(Inti dari tantangan adalah mendefinisikan metode / ekspresi yang memberikan jenis leksikografi yang benar. Beberapa bahasa mungkin memiliki jawaban yang lebih pendek dengan satu atau yang lain)

Anda tidak dapat menggunakan metode penguraian waktu internal (mis. strptime) Untuk menerjemahkan nama bulan menjadi angka atau pemetaan nama bulan yang sudah dilakukan sebelumnya. Gunakan properti dari string itu sendiri, tabel pencarian pelit yang Anda tentukan, atau sesuatu yang pintar.

Contoh

Contoh-contoh yang berfungsi, meskipun yang pertama dilarang oleh aturan ...

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

Versi di bawah ini OK, karena kami memberi kode informasi itu

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]

Atau Anda bisa melakukan fungsi sortir

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

Contoh tes

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')
Nick T
sumber
Anda tidak dapat menggunakan metode parsing waktu internal (mis. Strptime) untuk menerjemahkan nama bulan menjadi angka. Ini agak tidak jelas. Bisakah kita menggunakan literal bahasa standar yang berisi nama bulan?
Luis Mendo
Saya akan menghapus jawaban saya kemudian. Namun masih belum jelas apa yang diizinkan dan apa yang tidak.
Luis Mendo
Masalahnya adalah Anda tidak dapat mengantisipasi semua trik potensial tersebut, seperti array yang telah ditentukan sebelumnya. Mungkin pilihan yang lebih baik adalah menggunakan rangkaian string yang kurang umum, seperti nama-nama yang dibuat-buat. Tapi sekarang sudah terlambat untuk itu, kurasa
Luis Mendo
Apakah yang saya ungkapkan jelas? Jika Python memiliki builtin monthsyang merupakan daftar semua nama Bulan, saya ingin melarang months[x] < months[y]sebagai jawaban. Daftar nama bulan memiliki beberapa fitur yang lebih aneh (panjang bervariasi, kesamaan) yang membuat tantangan lebih mudah / lebih sulit daripada string yang dihasilkan secara acak.
Nick T
Ya, saya pikir sudah jelas. Saya hanya takut bahwa mungkin ada kasus serupa lainnya yang belum Anda singkirkan secara eksplisit (tapi saya tidak tahu yang mana)
Luis Mendo

Jawaban:

41

Jelly , 19 byte

11ị“bMAanlseovc”iµÞ

Ini adalah tautan monadik yang menjadikan daftar sebagai argumen dan mengurutkannya. Cobalah online!

Latar Belakang

Jelly menggunakan pengindeksan berbasis 1 modular. Jika kami cukup sering mengulangi nama bulan untuk mendapatkan 11 karakter, kami mendapatkan array berikut.

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

Di kolom ke- 11 (terakhir), semua karakter berbeda, sehingga kita dapat menggunakannya untuk mengidentifikasi urutan bulan.

Bagaimana itu bekerja

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).
Dennis
sumber
1
Hanya ingin tahu, bagaimana Anda menentukan peringkat bulan dengan "bMAanlseovc"? Indeks kecocokan karakter pertama?
ljeabmreosn
Saya telah menambahkan penjelasan.
Dennis
8
Wow, itu benar-benar pintar!
ljeabmreosn
15

kode mesin x86, 26 25 byte

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

Kode perakitan:

    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;

Fungsi hash berikut terjadi untuk menempatkan nama bulan dalam urutan yang benar (ditemukan oleh brute force):

(x ^ 0xc0) * 0x01435f30

Ini diterapkan pada 4 byte pertama (32 bit) dari string input, disusun dalam urutan little-endian. Kemudian membandingkan hasilnya dan menggunakan SALCuntuk mengatur register hasil:

  • -1 (benar) jika bulannya berurutan
  • 0 (salah) jika bulan kedua mendahului bulan pertama (atau keduanya sama)
anatolyg
sumber
4
Saya terkesan. Sepotong kode yang sangat singkat tanpa menggunakan bahasa khusus kode-golf.
ShuberFu
13

Jelly , 15 byte

Oḅ32 354*%991µÞ

Tidak ada tautan juru bahasa online di sini karena ini adalah satu pengiriman lambat . Program menggunakan fungsi hashing 354^(input interpreted as base 32 int) % 991sebagai kunci sortir, yang terjadi untuk memberikan output dalam urutan yang benar. Program ini tidak akan selesai dalam waktu dekat karena hasil dari eksponensial itu sangat besar - untuk "September", angka dengan 0,24 kuadriliun digit perlu dihitung!

Penjelasan jelly:

              Þ         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

Bukti skrip konsep Python - perhatikan penggunaan powuntuk eksponensial modular, yang jauh lebih efisien:

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))
Sp3000
sumber
5
"Tidak ada tautan penerjemah online di sini karena ini adalah satu pengiriman lambat ." Dalam hal ini, Anda bisa mengurutkan bulan dengan tangan. ;-)
owacoder
Mungkin Anda bisa mengajukan permintaan fitur untuk mengoptimalkan pow / mod ...
Nick T
@NickT Itu ide yang bagus, tapi sayangnya dengan cara interpreter mengatur (dengan masing-masing operator didefinisikan secara terpisah), itu mungkin sedikit rumit. Dan Jelly tidak bekerja dengan baik dengan operator yang memiliki lebih dari dua argumen, jadi mendefinisikan operator terpisah juga tidak akan berfungsi ...
Sp3000
Bukan operator terpisah atau apa pun, hanya beberapa introspeksi yang lebih dalam untuk melihat apakah operasi daya diikuti oleh divisi modular. Kedengarannya mudah? : P
Nick T
5

Python, 64 61 57 byte

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

Lambda membutuhkan waktu dua bulan sebagai masukan dan membandingkannya. Uji di Ideone .

Terima kasih kepada @ljeabmreosn untuk bermain golf 3 byte dan membuka jalan untuk 3 lagi!

Dennis
sumber
2
Akhirnya, Anda mengungkapkan rahasia di balik sihir hitam yang Anda gunakan untuk dengan cepat menghitung bulan yang benar dalam jawaban Jelly Anda!
Value Ink
1
Apakah perubahan s[10%len(s)]akan (4*s)[10]berhasil?
ljeabmreosn
1
@ ljeabmreosn Itu memang berhasil. Terima kasih!
Dennis
1
Belum melihat penggunaan <strike> ab </strike> dari argumen default di lambda: P
Nick T
4

Python, 81 71 byte

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

https://repl.it/CluN/1

Membandingkan indeks dalam mhuruf kedua dan ketiga dalam dua bulan.

Versi 83 byte untuk mengurutkan daftar bulan:

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

Ruby, 58 byte

Menggunakan trik penyortiran bulan dari jawaban @ atlasologist .

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

Fungsi perbandingan sedikit lebih lama, yaitu 63 byte

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

J, 66 65 byte

Menggunakan fakta bahwa f (m) = 2 * (ord (m [0]) + ord (m [-1])) // len (m) adalah fungsi yang valid dalam domain terbatas 12 bulan:

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

Pemakaian:

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

(Tidak berarti ini ide terbaik, tapi aku tidak ingin mencuri trik peringkat siapa pun!)

Ini adalah versi yang lebih pendek menggunakan metode @ atlasologist :

J, 63 byte

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

Pemakaian:

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

Dan versi yang jauh lebih pendek menggunakan metode pintar @ Dennis :

J, 34 byte

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

Haskell, 74 byte

Golf kode pertamaku, yay! Gagasan umum yang satu ini diilhami oleh jawaban teratas di Jelly, dan fakta bahwa ketika nama bulan di-siklus, karakter ke-11 selalu unik.

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

Berikut adalah versi yang tidak diklik untuk melihat cara kerjanya:

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)

The eFungsi merupakan fungsi eleventhChar (sayangnya tidak bisa menanggalkan 4 byte karena pembatasan monomorphism saya pikir) dan #berkorespondensi fungsi infiks keinOrder fungsi.

Solusi kecil yang rapi, tetapi mungkin ada cara untuk memotong lebih banyak byte (saya menemukan beberapa saat menulis ini!)

punjung
sumber
Anda bisa mempersingkat e s=head.drop 10$cycle sseperti yang Anda lakukan dalam penjelasan Anda dengan menggunakan .bukan $: e=head.drop 10.cycle. Namun menggunakan daftar indeks operator !!bahkan lebih pendek:e=(!!10).cycle
Laikoni
Saran yang bagus. Terkadang Anda mengabaikan hal-hal ini. Terima kasih banyak. Akan segera mengeditnya.
bower
2

Jawa, 133 123

Golf:

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

Saya sedang mencari teknik yang pintar seperti pada jawaban assembler, tetapi butuh waktu terlalu lama untuk mencari tahu jadi saya pergi dengan teknik yang sama yang digunakan orang lain.

Tidak Disatukan:

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

}

sumber
Anda dapat menggunakan substringsebagai gantinya jikacharAt
anatolyg
@anatolyg terima kasih, saya tidak yakin bagaimana yang satu itu lolos saya. Saya juga dapat menghapus "" +karena tidak ada bahan baku charlagi.
2

Bahasa mesin ARM di Linux 44 40 byte

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

Saya menggunakan fungsi hash yang berbeda dari anatolyg 's solusi dan mencoba untuk petunjuk penggunaan praktis untuk menyimpan beberapa byte (meskipun saya meniup 8 byte memasuki modus ibu jari).

Anda dapat mencobanya di Raspberry Pi atau perangkat Android dengan 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]);}

Untuk menjalankan, masukkan sesuatu seperti

$ ./foo January February; echo $?

Versi saat ini sekarang menangani kasus kesetaraan (dan lainnya) dengan benar.

plafon
sumber
Saya pikir Anda tidak perlu kode yang secara eksplisit beralih ke mode Jempol. Dari yang saya ingat, Anda hanya perlu memberi tahu linker bahwa prosedur Anda dalam mode jempol, dan linker akan menetapkan LSB di alamat prosedur Anda menjadi 1, sehingga prosesor akan beralih ke mode Jempol secara otomatis ketika kode Anda dipanggil.
anatolyg
Juga, apa fungsinya bfac?
anatolyg
@anatolyg secara ite gekondisional menjalankan instruksi berikutnya ( movge r0, #0) jika r3 >= r0, jika tidak, instruksi berikut ini dijalankan ( movlt r0, #1). Saya pikir ada ruang untuk membuat beberapa byte di sini, tetapi saya belum punya waktu untuk mengerjakan ini :-)
ceilingcat
1

Perl 6 , 55 byte

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

Dibutuhkan beberapa byte lagi untuk versi perbandingan:

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

Uji:

#! /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;
}
Brad Gilbert b2gills
sumber
1

Haskell, 118 karakter

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

Menggunakan fakta bahwa setiap nama bulan unik dalam karakter pertama dan keempatnya (atau 3 untuk Mei) untuk menentukan tipe data yang dapat diurai secara otomatis dan dibandingkan dengan bahasa. Fungsi 'r' mengubah string dengan meraih empat karakter pertama (atau lebih sedikit), lalu hanya memilih yang pertama dan terakhir. Maka 'a # b' adalah operator untuk membandingkan nilai:

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

Mungkin bisa dilakukan dengan cara yang lebih efisien, tetapi saya ingin mencoba melakukannya menggunakan tipe data yang berguna untuk mewakili bulan.

Jules
sumber
1

PowerShell, 96 88 63 byte

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

misalnya

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

Sekarang, lakukan tantangan kedua untuk menyortir daftar ke dalam urutan; versi sebelumnya melakukan perbandingan tes dua bulan:

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

Berdasarkan dua karakter kedua dalam nama bulan.

TessellatingHeckler
sumber
1

Python 83 82 byte

lambda x,y,m=(lambda a:'2&9<@FD6A?L%'.find(chr(sum(map(ord,a[:3]))%77))):m(x)<m(y)

Uji: https://repl.it/repls/TimelyDecimalBrowsers

Mendapat jumlah dari 3 karakter pertama dan membuat satu karakter untuk pencarian.

Baris
sumber
0

Javascript, 118 byte

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

Bisa bermain golf lebih banyak, mungkin dengan menyingkirkan cdan menggunakan array.map, tapi inilah yang saya miliki untuk saat ini ...

Botak Bantha
sumber
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 byte

ini berfungsi seperti 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}));}

uji

$ f January December && echo later || echo not later
not later
pengguna58494
sumber
0

k4, 29

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

Port jawaban @ Dennis's Jelly .

Ini adalah tukang sortir, bukan pembanding; Menariknya, komparator sepele diterapkan dengan algoritma yang sama, dan hanya satu byte lebih lama:

{(<)."ubMAanlseovc"?(*|11#)'x}
Aaron Davies
sumber
0

Bash + coreutils, 94 byte 93 byte

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

Ini adalah upaya untuk menghasilkan transformasi yang agak leksikografis. Jika Anda melihat dekat pada tombol transformasiFMAyulgSOND Anda dapat melihat bulan Februari hingga Desember (Januari menjadi kosong setelah transformasi; itu ditarik ke atas dengan menggunakan 'B' sebagai pemisah). Membalik, memotong, dan menghapus huruf yang tidak dikunci memungkinkan trik ini dibatalkan.

90 byte menggunakan C Lokal

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

... dimana ␉ adalah karakter tab.

80 byte menggunakan C Lokal

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

... menggunakan metode @ atlasolog. Terikat menjadi cara untuk menggunakan pendekatan ini untuk bekerja dengan lebih banyak lokal.

Tes / Penggunaan

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

output:

January
February
March
April
May
June
July
August
September
October
November
December
H Walters
sumber