Ordenar los meses del año

19

Escribir una función o programa que toma entradas de string, totalmente espelta, nombres ingleses mes en el caso del título: January, February, March, etc (nulo / CR / LF terminado bien, delimitado con un poco de carácter no-alfa si así lo desea) y, o bien

  • compara dos entradas, devolviendo un valor de Verdad si la segunda entrada es mayor (en orden de mes) que la primera. Los valores iguales dan como resultado un valor de Falsey

  • o ordena una secuencia arbitraria (lista, cadena delimitada, etc.) de ellos en orden cronológico

(El quid del desafío es definir un método / expresión que proporcione el tipo lexicográfico correcto. Algunos idiomas pueden tener una respuesta más corta con uno u otro)

No puede utilizar ningún método de análisis de tiempo interno (p strptime. Ej. ) Para traducir el nombre del mes en un número o una asignación preestablecida de nombres de mes. Utilice las propiedades de las cadenas en sí, una tabla de búsqueda parsimoniosa que defina o algo inteligente.

Ejemplo

Ejemplos de funcionamiento, aunque el primero está prohibido por las reglas ...

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

Sin embargo, las siguientes versiones están bien, porque codificamos esa información

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]

O podrías hacer una función de clasificación

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

Pruebas de ejemplo

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
fuente
No puede utilizar ningún método de análisis de tiempo interno (p. Ej., Strptime) para traducir el nombre del mes a un número. Esto es un poco confuso. ¿Podemos usar el literal predefinido de un idioma que contiene los nombres de los meses?
Luis Mendo
Eliminaré mi respuesta entonces. Pero aún no está claro qué está permitido y qué no.
Luis Mendo
El problema es que no puede anticipar todos esos trucos potenciales, como las matrices predefinidas. Quizás una mejor opción hubiera sido usar un conjunto de cadenas menos común, como nombres inventados. Pero ya es demasiado tarde para eso, supongo
Luis Mendo
¿Lo que estoy expresando es claro? Si Python tuviera una lista integrada monthsde todos los nombres de Mes, me gustaría prohibirla months[x] < months[y]como respuesta. La lista de nombres de mes tiene algunas características más peculiares (longitud variable, características comunes) que hacen que el desafío sea más fácil / difícil que las cadenas generadas aleatoriamente.
Nick T
Sí, creo que está claro. Solo temo que pueda haber otros casos similares que no haya descartado explícitamente (pero no sé cuáles)
Luis Mendo

Respuestas:

41

Jalea , 19 bytes

11ị“bMAanlseovc”iµÞ

Este es un enlace monádico que toma una lista como argumento y la ordena. Pruébalo en línea!

Antecedentes

Jelly utiliza indexación modular basada en 1. Si repetimos los nombres de los meses con la frecuencia suficiente para obtener 11 caracteres, obtenemos la siguiente matriz.

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

En la 11 ª columna (última), todos los personajes son diferentes, por lo que podemos utilizar para identificar el orden de los meses.

Cómo funciona

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
fuente
1
Por curiosidad, ¿cómo clasificas el mes con "bMAanlseovc"? Índice de la primera coincidencia de personajes?
ljeabmreosn
He añadido una explicación.
Dennis
8
Wow, eso es realmente inteligente!
ljeabmreosn
15

código de máquina x86, 26 25 bytes

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

Código de montaje:

    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 siguiente función hash pone los nombres de los meses en el orden correcto (encontrado por la fuerza bruta):

(x ^ 0xc0) * 0x01435f30

Se aplica a los primeros 4 bytes (32 bits) de la cadena de entrada, organizados en orden little-endian. Luego, compare el resultado y use SALCpara establecer el registro de resultados (al):

  • -1 (verdadero) si los meses están en orden
  • 0 (falso) si el segundo mes precede al primer mes (o son iguales)
anatolyg
fuente
44
Estoy impresionado. Una pieza de código muy corta sin usar lenguaje específico de código de golf.
ShuberFu
13

Jalea , 15 bytes

Oḅ32 354*%991µÞ

No hay un enlace de intérprete en línea aquí porque esta es una presentación lenta . El programa utiliza la función de hash 354^(input interpreted as base 32 int) % 991como la tecla de clasificación, que da resultados en el orden correcto. El programa no terminará pronto porque los resultados de la exponenciación son gigantes: para "septiembre", ¡se debe calcular un número con 0.24 billones de dígitos!

Explicación de gelatina:

              Þ         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 prueba de concepto de Python: tenga en cuenta el uso de powla exponenciación modular, que es mucho más eficiente:

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
fuente
55
"No hay un enlace de intérprete en línea aquí porque esta es una presentación lenta ". En cuyo caso, también puede ordenar los meses a mano. ;-)
owacoder
Tal vez podría PR una solicitud de función para optimizar pow / mod ...
Nick T
@NickT Esa es una excelente idea, pero desafortunadamente con la forma en que se configuró el intérprete (con cada operador definido por separado), eso podría ser un poco complicado. Y Jelly no funciona bien con operadores que tienen más de dos argumentos, por lo que definir un operador separado tampoco funcionaría ...
Sp3000
No es un operador separado ni nada, solo una introspección más profunda para ver si una operación de energía es seguida por una división modular. ¿Suena fácil? : P
Nick T
5

Python, 64 61 57 bytes

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

La lambda toma dos meses como entrada y los compara. Pruébalo en Ideone .

¡Gracias a @ljeabmreosn por jugar 3 bytes y allanar el camino para 3 más!

Dennis
fuente
2
¡Por fin, revelas el secreto detrás de la magia negra que usaste para calcular rápidamente el mes correcto en tu respuesta de Jelly!
Value Ink
1
¿Cambiaría s[10%len(s)]a (4*s)[10]trabajar?
ljeabmreosn
1
@ljeabmreosn Eso funciona de hecho. ¡Gracias!
Dennis
1
Todavía no he visto el uso de <strike> ab </strike> de argumentos predeterminados en una lambda: P
Nick T
4

Python, 81 71 bytes

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

https://repl.it/CluN/1

Compara el índice en mla segunda y tercera letra de dos meses.

Versión de 83 bytes para ordenar una lista de meses:

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

Ruby, 58 bytes

Utiliza el truco de clasificación mensual de la respuesta de @ atlasologist .

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

La función de comparación es un poco más larga, con 63 bytes.

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

J, 66 65 bytes

Utiliza el hecho de que f (m) = 2 * (ord (m [0]) + ord (m [-1])) // len (m) es una función válida en el dominio limitado de los 12 meses:

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

Uso:

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

(¡De ninguna manera esta es la mejor idea, pero no quería robar el truco de clasificación de nadie!)

Aquí hay una versión más corta usando el método de @ atlasologist :

J, 63 bytes

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

Uso:

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

Y una versión mucho más corta que usa el método inteligente de @ Dennis :

J, 34 bytes

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

Haskell, 74 bytes

Mi primer código de golf, ¡sí! La idea general de este se inspira en la respuesta principal en Jelly, y en el hecho de que cuando se completan los nombres de los meses, el undécimo personaje siempre es único.

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

Aquí hay una versión sin golf para ver cómo funciona:

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 efunción representa la undécima función de Char (lamentablemente no puedo eliminar 4 bytes debido a la restricción de monomorfismo, creo) y la #función infijo corresponde a la inOrderfunción.

Una pequeña solución ordenada, pero puede haber formas de eliminar más bytes (¡encontré algunas al escribir esto!)

cenador
fuente
Se podría acortar e s=head.drop 10$cycle sigual que lo hizo en su explicación usando .en lugar de $: e=head.drop 10.cycle. Sin embargo, usar el operador de índice de lista !!es aún más corto:e=(!!10).cycle
Laikoni
Grandes sugerencias A veces simplemente pasas por alto estas cosas. Muchas gracias. Lo editaré en breve.
Bower
2

Java, 133 123

Golfizado:

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

Estaba buscando una técnica inteligente como en la respuesta del ensamblador, pero me estaba tomando demasiado tiempo entenderlo, así que seguí con la misma técnica que todos los demás usaban.

Sin 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

}

fuente
En su substringlugar, podría usar sicharAt
anatolyg
@anatolyg gracias, no estoy seguro de cómo se me escapó. También pude eliminarlo "" +ya que ya no hay chars sin procesar .
2

Lenguaje de máquina ARM en Linux 44 40 bytes

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

He utilizado una función hash diferente que anatolyg 's solución y trató de instrucciones de uso del pulgar para ahorrar unos pocos bytes (aunque Soplé 8 bytes que entran en el modo de pulgar).

Puede probar esto en un dispositivo Raspberry Pi o Android con 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]);}

Para correr ingrese algo como

$ ./foo January February; echo $?

La versión actual ahora maneja el caso de igualdad (y otros) correctamente.

techo
fuente
Creo que no necesitas un código que cambie explícitamente al modo Thumb. Por lo que recuerdo, solo necesita decirle al vinculador que su procedimiento está en modo de pulgar, y el vinculador establecerá el LSB en la dirección de su procedimiento a 1, por lo que el procesador cambiará automáticamente al modo de pulgar cuando se llame su código.
anatolyg
Además, ¿qué hace bfac?
anatolyg
@anatolyg ite geejecuta condicionalmente la siguiente instrucción ( movge r0, #0) si r3 >= r0, de lo contrario, la instrucción que sigue se ejecuta ( movlt r0, #1). Creo que hay espacio para eliminar un par de bytes aquí, pero no he tenido tiempo de trabajar en esto :-)
ceilingcat
1

Perl 6 , 55 bytes

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

Requeriría unos pocos bytes más para las versiones de comparación:

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

Prueba:

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

Haskell, 118 caracteres

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

Utiliza el hecho de que el nombre de cada mes es único en su primer y cuarto caracteres (o el 3 de mayo) para definir un tipo de datos que el idioma puede analizar y comparar automáticamente. La función 'r' convierte una cadena al agarrar los primeros cuatro caracteres (o menos), luego solo elige el primero y el último. Entonces 'a # b' es un operador para comparar los valores:

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

Probablemente podría hacerse de una manera más eficiente, pero quería intentar hacerlo utilizando un tipo de datos útil para representar los meses.

Jules
fuente
1

PowerShell, 96 88 63 bytes

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

p.ej

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

Ahora hace el segundo desafío de ordenar una lista en orden; versiones anteriores hicieron la comparación de la prueba de dos meses:

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

Basado en los dos segundos caracteres del nombre del mes.

TessellatingHeckler
fuente
1

Python 83 82 bytes

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

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

Obtiene la suma de los primeros 3 caracteres y crea un único carácter para buscar.

Baris
fuente
0

Javascript, 118 bytes

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

Podría jugar más golf, probablemente al deshacerse de él cy usarlo array.map, pero esto es lo que tengo por ahora ...

Bantha calvo
fuente
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 bytes

esta es una función como 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}));}

prueba

$ f January December && echo later || echo not later
not later
usuario58494
fuente
0

k4, 29

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

Un puerto de respuesta de @ Dennis's Jelly .

Este es el clasificador, no el comparador; Curiosamente, el comparador es trivialmente implementable por el mismo algoritmo, y solo un byte más:

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

Bash + coreutils, 94 bytes 93 bytes

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

Este es un intento de llegar a una transformación que se clasifique lexicográficamente. Si observa de cerca la clave de transformación FMAyulgSOND, puede ver los meses de febrero a diciembre (enero se vacía después de la transformación; se tira hacia arriba mediante el uso de 'B' como separador). Invertir, truncar y eliminar letras sin clave permiten realizar este truco.

90 bytes usando C Locale

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

... donde ␉ es el carácter de tabulación.

80 bytes usando C Locale

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

... usando el método de @ atlasolog. Obligado a ser una forma de utilizar este enfoque para trabajar con más configuraciones regionales.

Prueba / uso

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

salidas:

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