Trier les mois de l'année

19

Écrivez une fonction ou un programme qui prend des entrées de chaînes, entièrement épeautre, les noms de mois Anglais en cas de titre: January, February, March, etc. (null / CR / LF fin OK, délimité par un caractère non-alpha si vous le souhaitez) et soit

  • compare deux entrées, renvoyant une valeur Truthy si la deuxième entrée est supérieure (dans l'ordre du mois) à la première. Des valeurs égales donnent une valeur Falsey

  • ou en trie une séquence arbitraire (liste, chaîne délimitée, etc.) dans un ordre chronologique

(Le nœud du défi est de définir une méthode / expression qui donne le bon tri lexicographique. Certaines langues peuvent avoir une réponse plus courte avec l'une ou l'autre)

Vous ne pouvez pas utiliser de méthodes d'analyse temporelle interne (par exemple strptime) pour traduire le nom du mois en un nombre ou un mappage prédéfini des noms de mois. Utilisez les propriétés des chaînes elles-mêmes, une table de recherche parcimonieuse que vous définissez ou quelque chose d'intelligent.

Exemple

Exemples de fonctionnement, bien que le premier soit interdit par les règles ...

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

Les versions ci-dessous sont correctes, car nous codons ces informations

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]

Ou vous pouvez faire une fonction de tri

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

Exemples de tests

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
la source
Vous ne pouvez pas utiliser de méthodes d'analyse temporelle interne (par exemple strptime) pour traduire le nom du mois en nombre. C'est un peu flou. Peut-on utiliser le littéral prédéfini d'une langue qui contient les noms des mois?
Luis Mendo
Je supprimerai alors ma réponse. Mais on ne sait toujours pas ce qui est autorisé et ce qui ne l'est pas.
Luis Mendo
Le problème est que vous ne pouvez pas anticiper toutes ces astuces potentielles, telles que les tableaux prédéfinis. Une meilleure option aurait peut-être été d'utiliser un ensemble de chaînes moins courant, comme des noms composés. Mais il est trop tard maintenant pour ça, je suppose
Luis Mendo
Ce que j'exprime est-il clair? Si Python avait un intégré monthsqui était une liste de tous les noms de mois, je voudrais interdire months[x] < months[y]comme réponse. La liste des noms de mois a des caractéristiques plus particulières (longueur variable, similitude) qui rendent le défi plus facile / plus difficile sur les chaînes générées de manière aléatoire.
Nick T
Oui, je pense que c'est clair. Je crains simplement qu'il puisse y avoir d'autres cas similaires que vous n'avez pas explicitement exclus (mais je ne sais pas lesquels)
Luis Mendo

Réponses:

41

Gelée , 19 octets

11ị“bMAanlseovc”iµÞ

Il s'agit d'un lien monadique qui prend une liste en argument et la trie. Essayez-le en ligne!

Contexte

Jelly utilise une indexation modulaire basée sur 1. Si nous répétons les noms de mois assez souvent pour obtenir 11 caractères, nous obtenons le tableau suivant.

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

Dans la 11 e (dernière) colonne, tous les caractères sont différents, nous pouvons donc les utiliser pour identifier l'ordre des mois.

Comment ça fonctionne

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
la source
1
Juste curieux, comment classez-vous le mois avec "bMAanlseovc"? Index de la première correspondance de caractères?
ljeabmreosn
J'ai ajouté une explication.
Dennis
8
Wow, c'est vraiment intelligent!
ljeabmreosn
15

code machine x86, 26 25 octets

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

Code d'assemblage:

    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;

La fonction de hachage suivante arrive à mettre les noms de mois dans le bon ordre (trouvé par force brute):

(x ^ 0xc0) * 0x01435f30

Il est appliqué aux 4 premiers octets (32 bits) de la chaîne d'entrée, disposés en ordre petit-boutien. Ensuite, comparer le résultat et utiliser SALCpour définir le registre de résultat (al):

  • -1 (vrai) si les mois sont en ordre
  • 0 (faux) si le deuxième mois précède le premier mois (ou ils sont identiques)
anatolyg
la source
4
Je suis impressionné. Un morceau de code très court sans utiliser de langage spécifique au code-golf.
ShuberFu
13

Gelée , 15 octets

Oḅ32 354*%991µÞ

Pas de lien d'interprète en ligne ici car il s'agit d'une soumission lente . Le programme utilise la fonction de hachage 354^(input interpreted as base 32 int) % 991comme clé de tri, ce qui donne des sorties dans le bon ordre. Le programme ne se terminera pas de si tôt car les résultats de l'exponentiation sont géants - pour "septembre", un nombre à 0,24 quadrillion de chiffres doit être calculé!

Explication de la gelée:

              Þ         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

Script de preuve de concept Python - notez l'utilisation de powpour l'exponentiation modulaire, qui est beaucoup plus efficace:

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
la source
5
"Pas de lien d'interprète en ligne ici car il s'agit d'une soumission lente ." Dans ce cas, vous pouvez également trier les mois à la main. ;-)
owacoder
Peut-être que vous pourriez PR une demande de fonctionnalité pour optimiser pow / mod ...
Nick T
@NickT C'est une excellente idée, mais malheureusement avec la configuration de l'interpréteur (avec chaque opérateur défini séparément), cela pourrait être un peu délicat. Et Jelly ne fonctionne pas bien avec les opérateurs qui ont plus de deux arguments, donc définir un opérateur séparé ne fonctionnerait pas non plus ...
Sp3000
Pas un opérateur séparé ou quoi que ce soit, juste une introspection plus profonde pour voir si une opération d'alimentation est suivie d'une division modulaire. Cela semble facile? : P
Nick T
5

Python, 64 61 57 octets

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

Le lambda prend deux mois en entrée et les compare. Testez-le sur Ideone .

Merci à @ljeabmreosn pour avoir joué au golf sur 3 octets et ouvert la voie à 3 autres!

Dennis
la source
2
Enfin, vous dévoilez le secret de la magie noire que vous avez utilisée pour calculer rapidement le bon mois dans votre réponse Jelly!
Value Ink
1
Est-ce que changer s[10%len(s)]pour (4*s)[10]travailler?
ljeabmreosn
1
@ljeabmreosn Cela fonctionne en effet. Merci!
Dennis
1
Je n'ai pas encore vu l'utilisation <strike> ab </strike> des arguments par défaut dans un lambda: P
Nick T
4

Python, 81 71 octets

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

https://repl.it/CluN/1

Compare l'indice dans mles deuxième et troisième lettres de deux mois.

Version 83 octets pour trier une liste de mois:

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

Rubis, 58 octets

Utilise l'astuce de tri par mois de la réponse de @ atlasologist .

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

La fonction de comparaison est un peu plus longue, à 63 octets

->a,b{m=->i{"anebarprayunulugepctovec".index i[1,2]};m[a]<m[b]}
Encre de valeur
la source
3

J, 66 65 octets

Utilise le fait que f (m) = 2 * (ord (m [0]) + ord (m [-1])) // len (m) est une fonction valide dans le domaine limité des 12 mois:

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

Usage:

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

(En aucun cas, ce n'est la meilleure idée, mais je ne voulais pas voler l'astuce de classement de quelqu'un!)

Voici une version plus courte utilisant la méthode de @ atlasologist :

J, 63 octets

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

Usage:

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

Et une version beaucoup plus courte utilisant la méthode intelligente de @ Dennis :

J, 34 octets

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

Haskell, 74 octets

Mon premier code de golf, yay! L'idée générale de celui-ci est inspirée de la réponse la plus élevée dans Jelly et du fait que lorsque les noms de mois sont cyclés, le 11e caractère est toujours unique.

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

Voici une version non golfée pour voir comment cela fonctionne:

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)

La efonction représente la fonction eleventhChar (malheureusement ne peut pas supprimer 4 octets en raison de la restriction du monomorphisme, je pense) et la #fonction infixe correspond à la inOrderfonction.

Une petite solution intéressante, mais il peut y avoir des moyens de raser plus d'octets (j'en ai trouvé juste en écrivant ceci!)

tonnelle
la source
Vous pouvez raccourcir e s=head.drop 10$cycle scomme vous l'avez fait dans votre explication en utilisant au .lieu de $: e=head.drop 10.cycle. Cependant, l'utilisation de l'opérateur d'index de liste !!est encore plus courte:e=(!!10).cycle
Laikoni
Excellentes suggestions. Parfois, vous oubliez simplement ces choses. Merci beaucoup. Le modifierai sous peu.
bower
2

Java, 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));}

Je cherchais une technique intelligente comme dans la réponse de l'assembleur, mais cela prenait trop de temps à comprendre, alors j'ai opté pour la même technique que tout le monde a utilisée.

Non golfé:

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

}

la source
Vous pouvez utiliser à la substringplace sicharAt
anatolyg
@anatolyg merci, je ne sais pas comment celui-là m'a échappé. J'ai également pu supprimer "" +car il n'y a plus de chars bruts .
2

Langage machine ARM sous Linux 44 40 octets

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

J'ai utilisé une fonction de hachage différente de la solution d ' anatolyg et j'ai essayé d' utiliser les instructions du pouce pour économiser quelques octets (bien que j'ai soufflé 8 octets en mode pouce).

Vous pouvez essayer cela sur un appareil Raspberry Pi ou Android avec 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]);}

Pour exécuter, entrez quelque chose comme

$ ./foo January February; echo $?

La version actuelle gère désormais correctement le cas d'égalité (et d'autres).

plafond
la source
Je pense que vous n'avez pas besoin de code qui passe explicitement en mode Thumb. D'après ce dont je me souviens, il vous suffit de dire à l'éditeur de liens que votre procédure est en mode pouce, et l'éditeur de liens définira le LSB dans l'adresse de votre procédure sur 1, de sorte que le processeur passera automatiquement en mode pouce lorsque votre code sera appelé.
anatolyg
Et qu'est-ce que ça bfacfait?
anatolyg
@anatolyg ite geexécute conditionnellement l'instruction suivante ( movge r0, #0) si r3 >= r0, sinon l'instruction suivante qui est exécutée ( movlt r0, #1). Je pense qu'il y a de la place pour supprimer quelques octets ici, mais je n'ai pas eu le temps d'y travailler :-)
plafondcat
1

Perl 6 , 55 octets

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

Il faudrait quelques octets de plus pour les versions de comparaison:

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

Tester:

#! /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
la source
1

Haskell, 118 caractères

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

Utilise le fait que le nom de chaque mois est unique dans ses premier et quatrième caractères (ou 3ème pour mai) pour définir un type de données qui peut être automatiquement analysé et comparé par la langue. La fonction «r» convertit une chaîne en saisissant les quatre premiers caractères (ou moins), puis en sélectionnant simplement le premier et le dernier. Alors 'a # b' est un opérateur pour comparer les valeurs:

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

Cela pourrait probablement être fait de manière plus efficace, mais je voulais essayer de le faire en utilisant un type de données utile pour représenter les mois.

Jules
la source
1

PowerShell, 96 88 63 octets

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

par exemple

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

Maintenant, le deuxième défi consiste à trier une liste dans l'ordre; les versions précédentes faisaient la comparaison du test de deux mois:

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

Basé sur les deux seconds caractères du nom du mois.

TessellatingHeckler
la source
1

Python 83 82 octets

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

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

Obtient la somme des 3 premiers caractères et crée un seul caractère à rechercher.

Baris
la source
0

Javascript, 118 octets

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

Pourrait être joué au golf plus probablement en se débarrassant cet en utilisant array.map, mais c'est ce que j'ai pour l'instant ...

Chauve Bantha
la source
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 octets

c'est une fonction comme 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}));}

tester

$ f January December && echo later || echo not later
not later
user58494
la source
0

k4, 29

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

Un port de @ Dennis's Jelly répond .

C'est le trieur, pas le comparateur; intéressant, le comparateur est trivialement implémentable par le même algorithme, et un seul octet de plus:

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

Bash + coreutils, 94 octets 93 octets

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

Il s'agit d'une tentative de proposer une transformation qui trie lexicographiquement. Si vous regardez attentivement la clé de transformation, FMAyulgSONDvous pouvez voir les mois de février à décembre (janvier devient vide après la transformation; il est tiré vers le haut en utilisant «B» comme séparateur). Inverser, tronquer et supprimer des lettres non saisies permet de réaliser cette astuce.

90 octets utilisant C Locale

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

... où ␉ est le caractère de tabulation.

80 octets utilisant C Locale

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

... en utilisant la méthode de @ atlasolog. Lié comme un moyen d'utiliser cette approche pour travailler avec plus de paramètres régionaux.

Test / utilisation

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

les sorties:

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