排序一年中的月份


19

编写一个函数或程序,需要字符串输入,完全拼写,英语月份名称首字母大写:JanuaryFebruaryMarch等(空/ CR / LF终止OK,分隔与一些非字母字符,如果你选择),要么

  • 比较两个输入,如果第二个输入(按月顺序)大于第一个输入,则返回True值。相等的值导致Falsey值

  • 或按时间顺序对它们的任意序列(列表,定界字符串等)进行排序

(挑战的症结在于定义一种方法/表达式,以给出正确的词典编排排序。某些语言对另一种语言的回答可能较短)

您不能使用任何内部时间解析方法(例如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]做。月份名称列表具有一些更特殊的功能(长度,通用性),这使得对随机生成的字符串的挑战更容易/更困难。
尼克T

是的,我认为这很清楚。我只是担心您可能还没有明确排除其他类似情况(但我不知道是哪种情况)
Luis Mendo

Answers:


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字节

十六进制转储:

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(true)如果月份正确
  • 如果第二个月早于第一个月(或它们相同),则为0(否)

4
我印象深刻 一段很短的代码,而不使用特定于代码高尔夫的语言。
ShuberFu

13

果冻,15 字节

Oḅ32 354*%991µÞ

这里没有在线解释器链接,因为这是一个缓慢的提交。该程序使用哈希函数354^(input interpreted as base 32 int) % 991作为排序键,恰好以正确的顺序给出输出。该程序不会很快结束,因为取幂的结果非常巨大-对于“ 9月”,需要计算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

也许您可以提出一项功能请求,以优化战俘/战利品...
Nick T

@NickT这是一个好主意,但是不幸的是,解释器的设置方式(每个运算符分别定义)可能有点棘手。而且Jelly无法与具有两个以上参数的运算符配合使用,因此定义一个单独的运算符也将无法正常工作...
Sp3000

不是一个单独的运算符或其他任何东西,而是更深入的内省,以查看是否在进行幂运算后进行模块化除法。听起来容易吗?:P
尼克T

5

Python,64 61 57字节

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

Lambda需要两个月作为输入并进行比较。在Ideone上进行测试

感谢@ljeabmreosn打出3个字节并为另外3个字节铺平了道路!


2
最后,您将揭示用于快速计算果冻答案中正确月份的黑魔法背后的秘密!
价值墨水

1
会改变s[10%len(s)](4*s)[10]工作?
ljeabmreosn

1
@ljeabmreosn确实有效。谢谢!
丹尼斯,

1
尚未在lambda中看到<strike> ab </ strike>默认参数的使用:P
Nick T

4

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

Ruby,58个字节

使用@atlasologist的答案中的月份排序技巧。

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

比较功能要长一点,为63字节

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

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个字节),而#infix函数对应于该inOrder函数。

一个小巧的解决方案,但是可能有一些方法可以减少更多的字节(我在编写此文件时发现了一些!)


您可以e s=head.drop 10$cycle s使用.而不是来缩短解释时的$时间e=head.drop 10.cycle。但是,使用列表索引运算符!!的时间更短:e=(!!10).cycle
Laikoni '16

很棒的建议。有时您只是忽略了这些事情。非常感谢。不久将对其进行编辑。
Bower

2

Java中,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,而不是如果charAt
anatolyg

@anatolyg谢谢,我不确定那个人是如何逃离我的。我也可以删除,"" +因为char不再有raw 了。

2

Linux 44上的ARM机器语言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

我用比不同的哈希函数anatolyg溶液,并试图使用拇指指令来保存几个字节(尽管我吹8个字节进入拇指模式)。

您可以在具有GNURoot的Raspberry Pi或Android设备上进行尝试。

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 $?

现在,当前版本可以正确处理相等情况(和其他情况)。


我认为您不需要显式切换到Thumb模式的代码。据我所记得,您只需要告诉链接器您的过程处于Thumb模式,并且链接器会将您过程的地址中的LSB设置为1,因此在调用您的代码时处理器将自动切换到Thumb模式。
anatolyg

另外,该怎么bfac办?
anatolyg

@anatolyg如果ite ge有条件地执行下一条指令(movge r0, #0r3 >= r0,否则执行下一条指令(movlt r0, #1)。我认为这里有空间可以
删除

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

使用每个月的名称在其第一个和第四个字符(或5月的第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

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

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您会看到2月到12月的月份(转换后1月变空;使用'B'作为分隔符将其拉到顶部)。反向,截断和删除非键字母可以使此技巧生效。

使用C语言环境的90个字节

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

...其中␉是制表符。

使用C语言环境的80个字节

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
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.