从列表中生成带有牛津逗号的单个字符串


24

有什么巧妙的(简短而惯用的)方法来获取字符串列表,并返回一个从列表中构建的正确标点的字符串,并用引号将每个元素引起来。

这是我在尝试Groovy时想到的,对于我来说,我的字面意思是,但过于说明性的解决方案是

def temp = things.collect({"\'${it}\'"})
switch (things.size()) {
    case 1:
        result = temp[0]
        break
    case 2:
        result = temp.join(" and ")
        break
    default:
        result = temp.take(temp.size()-1).join(", ") + ", and " + temp[-1]
        break
}

也就是说,['1']应该yield '1'['1','2']应该yield '1 and 2',[请参阅我在那里做的吗?],并且['1','2','3']应该yield '1, 2, and 3'

对于Groovy,我有一些很好的答案,但我想看看其他语言可以做什么。

在各种语言中,有什么紧凑的巧妙方法可以利用这些语言的功能和习惯用法?


6
欢迎来到PPCG。通常,此处发布的问题是对社区的挑战。因此,他们需要一个客观的获胜标准。我相信这个问题可以很好地映射为代码高尔夫挑战。您可以这样标记吗?如果是这样,我认为您应该收紧输入和输出规范。
Digital Trauma

7
实际句子会更有趣:['we invited the stripper','JFK','Stalin']
ThisSuitIsBlackNotNot 2014年

1
我们可以假设字符串本身已经不包含逗号吗?
Martin Ender 2014年

2
挑战本应标题为“谁给了---- 牛津逗号?”
Igby Largeman 2014年

3
@OldCurmudgeon我想你的意思是“美国垃圾”;)
ThisSuitIsBlackNotNot

Answers:


76

CSS,132个 116 115字节

a:not(:last-child):nth-child(n+2):after,a:nth-last-child(n+3):after{content:","}a+:last-child:before{content:"and "

在代码高尔夫中,CSS并不是很常见,因为它只能格式化文本,但是它确实可以应对这一挑战,我认为这样做很有趣。使用上面的代码片段查看实际运行情况(单击“显示代码片段”)。

列表应位于链接的HTML文件中,每个元素都用<a>标签包围,并用换行符分隔。列表项应该是其父元素中唯一的元素,例如

<a>one</a>
<a>two</a>
<a>three</a>

说明

a:not(:last-child):nth-child(n+2)::after,
a:nth-last-child(n+3)::after {
    content: ",";
}

a + :last-child::before {
    content: "and ";
}

让我们考虑上面的非高尔夫版本。如果您不熟悉CSS的工作方式,则花括号外的所有内容都是一个选择器,用于确定花括号内的声明所适用的HTML元素集。每个选择器-声明对称为规则。(比这要复杂得多,但足以满足此说明的要求。)在应用任何样式之前,列表似乎仅由空格分隔。

我们希望在除最后一个单词之外的每个单词之后添加逗号,但两个单词列表除外,该列表没有逗号。第一个选择器,a:not(:last-child):nth-child(n+2):after选择第一个和最后一个元素之外的所有元素。:nth-child(n+2)是一种简短的说法:not(:first-child),它基本上是通过选择索引(从1开始)大于或等于2的元素来工作的(是的,它仍然让我有些困惑。MDN文档可能会有所帮助。)

现在,如果总共有三个或更多元素,我们只需要选择第一个元素即可得到逗号。a:nth-last-child(n+3):after的工作方式与相似:nth-child,但从背面开始计数,因此它将选择除最后两个元素以外的所有元素。逗号采用两组的并集,我们使用:after 伪元素content在每个选定元素之后立即添加。

第二条规则比较容易。我们需要在列表中的最后一个元素之前添加“ and”,除非它是单个元素。换句话说,我们需要选择在另一个元素之后的最后一个元素。+是CSS中相邻的兄弟选择器


1
辉煌!我喜欢它。:D
COTO

如果您愿意的话<li>
slebetman 2014年

1
<li>会很理想,但这会在选择器中添加两个额外的字符。我选择<a>它是因为它是一个字母,并且不应用自己的格式。
NinjaBearMonkey 2014年

哇,这真令人印象深刻。聪明奖。

CSS作为最佳答案?真好
布兰登

13

Haskell:81、77 74个字符

f[x]=x
f[x,y]=x++" and "++y
f[x,y,z]=x++", "++f[y++",",z]
f(x:y)=x++", "++f y

Haskell功能:模式匹配


您可以删除一些空格
Ray

1
您可以删除f[x,y,z]
Seequ 2014年

现在,这几乎是标准的递归。:)
seequ 2014年

您在逗号后忘记了牛津逗号和空格- f["a","b","c"]应该是,"a, b, and c"但是"a,b and c"
骄傲的haskeller 2014年

4
如何通过替换y++", and "++zf[y++",",z]:)来打高尔夫球?
骄傲的haskeller 2014年

7

Ruby,47个字节

q=" and ";p$*[2]?(a=$*.pop;$**", "+?,+q+a):$**q

说明

  • 输入是命令行参数($*)。
  • $*具有第三个元素($*[2]不返回nil)时,将所有元素减去最后一个元素,然后使用将其转换为逗号分隔的String Array#*。最后,添加一个额外的逗号,字符串" and "和最后一个命令行参数。
  • $*没有第三个元素时,给出两个,一个或零个参数。参数可以安全地与字符串连接" and "并产生正确的结果。

6

的Python 2(61)

s=input()
d=s.pop()
print", ".join(s)+", and "[8-7*len(s):]+d

主要技巧是", and "为一个和两个元素切断最终连接器的一部分。首先,将其全部切掉,对于两个,将逗号删除。这是通过切出来完成的[8-7*len(s):](请注意,s它比短一pop)。

不幸的是,d不能仅仅用它的表达方式来代替,否则pop会为时已晚。


你可以替换第一个ss=input(),并删除第一行,如果我没有记错。节省2个字符。
tomsmeding

@tomsmeding我不明白您的建议。该代码s多次引用。
xnor

等等,今天早上我做些奇怪的事情。算了 :)
tomsmeding

6

CSS, 62个字符 112个字符

受到其他条目的启发,甚至更短。请注意,它要求A元素不能用空格分隔:

a+a:before{content:", "}a+a:last-child:before{content:", and "

http://jsfiddle.net/olvlvl/1Ls79ocb/

修正丹尼斯指出的“一和二”:

a+a:before{content:", "}a+a:last-child:before{content:", and "}a:first-child+a:last-child:before{content:" and "

http://jsfiddle.net/olvlvl/1Ls79ocb/3/


5

Perl(v 5.10+)- 37 35 34 28

@F>2&&s/ /, /g;s/.* \K/and /

与之一起perl -ape使用,列表中提供的空格分开STDIN

各种输入的输出:

$ perl -ape '@F>2&&s/ /, /g;s/.* \K/and /'
oxford
oxford
oxford cambridge
oxford and cambridge
oxford cambridge comma
oxford, cambridge, and comma
oxford cambridge comma space
oxford, cambridge, comma, and space

您可以通过将最后一个替换项更改为s/(\S+)$/and $1/
ThisSuitIsBlackNotNot

1
@ThisSuitIsBlackNot您可以删除“ \ n”(谢谢),但不能删除空格,或者输入的“ x”变为“ and x”
大约

糟糕,应该用更多的输入进行测试。反正你忘了$编辑中锚点,因此输入foo bar baz变为foo, and bar, baz。此外,您可以通过执行以下操作删除其中一个空格s/( \S+)$/ and$1/
ThisSuitIsBlackNotNot

我最后的评论仍然留下你35,你还可以写$#F>1@F>2剃掉一个。抱歉所有关于微改进的建议,我真的很喜欢这个答案:)
ThisSuitIsBlackNotNot

@ThisSuitIsBlack完全不是-欢迎微编辑。我正在秘密地与28字节的CJam和30字节的Golfscript竞争。但是我确实做到了34,而没有做完最后一个注释的翻译(使用进行了测试echo -n ... | wc -c)。如果您在(\S+)输入33个字符之前错过空格,但是如果您输入test thistest and this了空格您将得到(之后的两个空格test),所以没有更多我认为这是错误的
2014年

4

Javascript(63)

l=a.length;l>2&&(a[l-1]='and '+a[l-1]);a.join(l>2?', ':' and ')

情况:

  • a = [1] => 1
  • a = [1, 2] => 1 and 2
  • a = [1, 2, 3] => 1, 2, and 3

警告:这将修改长度大于2的数组中的最后一个元素。


2
很好的使用&&
Chris Bloom 2014年

4

GNU sed-69个字符,其中1个用于-r标志

s/ /, /g
s/( [^ ]+)( [^ ]+)$/\1 and\2/
s/^([^,]+),([^,]+)$/\1 and\2/

取得一个以空格分隔的列表(对于shell脚本来说,这是惯用的)。

$ sed -r -f oxfordcomma.sed <<< "1"
1
$ sed -r -f oxfordcomma.sed <<< "1 2"
1 and 2
$ sed -r -f oxfordcomma.sed <<< "1 2 3"
1, 2, and 3
$

是的,让我们来看一下代码高尔夫
orome 2014年

第二个输出应1 and 21, 2
Optimizer

@Optimizer-非常正确。固定。
Digital Trauma 2014年

3

Python 2-71,70 68

s=input()
l=len(s)-1
print', '.join(s[:l])+', and '[l<2:]*(l>0)+s[l]

字符数,包括inputprint


3

Ruby,57个字节

f=->l{s=l*', ';s.sub(/,(?!.*,)/,(l.size<3?'':?,)+' and')}

我先加入字符串,,然后再将字符串中的最后一个逗号替换为and(以及可选的逗号,具体取决于列表的长度)。


3

眼镜蛇-60

do(l as String[])=l.join(', ',if(l.length<3,'',',')+' and ')

Cobra的List<of T>.join功能允许您为列表的最后两个元素指定不同的分隔符,这就是为什么这么短。


3

Perl-59

sub f{$a=join', ',@_;$#_&&substr$a,(@_>2)-3,@_<3,' and';$a}

用逗号连接列表,然后,如果列表具有多个元素,则' and'在最后一个逗号后添加(如果长度> = 3),或用最后一个逗号替换最后一个逗号(如果长度== 2)。


3

PHP,192个 167 146 136字符:

$n=' and ';$s=count($a);echo ($s<3)?join($n,$a):join(', ',array_merge(array_slice($a,0,$s-2),Array(join(",$n",array_slice($a,-2,2)))));

基于我几年前在http://www.christopherbloom.com/2011/05/21/join-implode-an-array-of-string-values-with-formatting/上编写的函数


您能否将您的代码(带有牛津逗号)放入答案文本?

是的对不起 我在手机上,无法正确粘贴代码。我将从桌面上进行更新
Chris Bloom 2014年

@ Chrisbloom7即使添加起来很简单,答案也应该包括一个有效的代码,而不是一个可以成为一个的代码。同样,由于目标是使代码尽可能小,因此不发布有效代码会使您的分数不存在。
骄傲的haskeller 2014年

再次道歉。CG的第一次海报。我已经解决了我的问题
克里斯·布鲁姆

3

批次-151字节

@echo off&set f=for %%a in (%~1)do
%f% set/aa+=1
%f% set/ac+=1&if !c!==1 (set o=%%a)else if !c!==!a! (set o=!o!, and %%a)else set o=!o!, %%a
echo !o!

注意; 您必须cmd通过将/v开关设置为来调用脚本on,因此,我不必setLocal enableDelayedExpansion在脚本中包含冗长的内容。否则,在字节数上加30,然后正常调用脚本。

h:\uprof>cmd /von /c test.bat "1 2 3"
1, 2, and 3

h:\uprof>cmd /von /c test.bat "1 2 3 4 5"
1, 2, 3, 4, and 5

3

Groovy,47岁43 57个字符,JavaScript ES6 56个字符

Groovy:

(a[1]?a[0..-2].join(", ")+(a[2]?",":"")+" and ":"")+a[-1]

由于数组中填充了字符,因此我们可以替换a.size>1a[1]

JavaScript,ES6:

a.join(', ').replace(/,([^,]+)$/,`${a[2]?',':''} and$1`)

两种情况都假定变量a具有所讨论的数组。


6
牛津逗号是合取之前的逗号。
丹尼斯

3

PHP,86 84个字符

$a = ['one', 'two', 'three', 'four', 'five'];

初始化数组后,我们开始计数:

$L=count($a)-1;$S=', ';$L<2?($S=' and '):($a[$L]='and '.$a[$L]);echo implode($S,$a);

美化:

$last_index = count($a) - 1;
$separator = ', ';
if ($last_index < 2) {
    $separator = ' and ';
} else {
    $a[$last_index] = 'and '.$a[$last_index];
}
echo implode($separator, $a);

列表中的最后一项被修改。这应该没问题,因为在PHP中,数组赋值和函数调用执行副本。


3

CJam,35 30 28 27字节

q~)\_"and "L?@+a+_,2=", ">*

这是一个从STDIN读取并打印到STDOUT的程序。 在线尝试。

怎么运行的

q~                                     " Q := eval(input())                               ";
  )                                    " P := Q.pop()                                     ";
   \_"and "L?@+                        " P := (Q ? 'and ' : '') + P                       ";
                a+                     " Q += [P]                                         ";
                  _,2=", ">            " J := ', '[(len(Q) == 2):]                        ";
                           *           " R := J.join(Q)                                   ";
                                       " print R (implicit)                               ";

运行示例

$ cjam <(echo 'q~)\_"and "L?@+a+_,2=", ">*') <<< '["1"]'; echo
1
$ cjam <(echo 'q~)\_"and "L?@+a+_,2=", ">*') <<< '["1""2"]'; echo
1 and 2
$ cjam <(echo 'q~)\_"and "L?@+a+_,2=", ">*') <<< '["1""2""3"]'; echo
1, 2, and 3
$ cjam <(echo 'q~)\_"and "L?@+a+_,2=", ">*') <<< '["1""2""3""4"]'; echo
1, 2, 3, and 4

我在你的尾巴上-见下文:-)
大约

3

Google表格,67 68 67 92字节

=SUBSTITUTE(JOIN(", ",FILTER(A:A,A:A<>"")),",",IF(COUNTA(A:A)>2,",","")&" and",COUNTA(A:A)-1

输入从单元格开始,A1然后继续向下,但存在许多条目。
JOIN将它们合并成一个字符串,每个字符串之间用逗号隔开。
FILTER删除所有非空格,这样一来您就不会以逗号结尾。
SUBSTITUTE替换最后一个逗号(由COUNTA计算非空白输入来找到)。

这不是很令人兴奋,但可以在单个单元中完成。


这样就排除了牛津逗号。
伞”

@雨伞好吧,那真是我的愚蠢,不是吗?+1个字节
Engineer Toast

您应该可以将终端)从此公式中删除-1字节;好吧,这是我见过最快的编辑+1
Taylor Scott Scott

经过测试的两个注释- A:A>""应该转换为A:A<>"",并且不会在只有2个对象的情况下省略牛津逗号
Taylor Scott

@TaylorScott我想我只测试过文本,而错过了问题>""。我先前所做的快速校正显然没有经过测试。我不喜欢的方向去...
工程师吐司

2

JavaScript(ES6)60

假设输入数组中没有空字符串

f=(a,b=a.pop())=>a[0]?a.join(', ')+(a[1]?',':'')+' and '+b:b

在FireFox / Firebug控制台中测试

console.log(f(['We invited the stripper','JFK','Stalin']))

输出量

 We invited the stripper, JFK, and Stalin

我该如何运行?我node --harmony用一串字符串试了一下var a = 'abcdefgh'.split('');,但是它只是放在一个...,看上去什么也没做。还可以+1以使用独特的ES6功能()=>
阿德里安

@Adrian该函数返回一个字符串,没有任何输出。我将在答案中添加一个测试。
edc65

我认为f=(a,b=a.pop())=>a[0]?a.join(', ')+', and '+b:b也是正确的,并且短了13个字节。
IngoBürk2014年

1
@IngoBürk剪切处理带有2个项目的逗号的部分。你猜怎么了?如果有2个项目,则输出错误。
edc65 2014年

@ edc65啊,天哪。可能不好。
IngoBürk2014年

2

JavaScript- 60 56 71 67 63

这不完全是一种惯用的方法,但是我很喜欢编写它,并且我喜欢正则表达式。

假设数组存储在var a

a.join((a.length>2?',':'')+' ').replace(/([^,\s])$/,"and $1")

只需检查索引即可缩短[2]:(是,布尔强制)

a.join((!!a[2]?',':'')+' ').replace(/([^,\s])$/,'and $1')

显然,我很讨厌测试,并且跳过了单项测试。这是固定版本:

a.join((!!a[2]?',':'')+' ').replace(/([^,\s])$/,(!!a[1]?'and ':'')+'$1')

通过将我的布尔值反转来减少2个字符,并通过将空间从串联中移到第一个三元组的then / else中来减少3个字符:

a.join((!a[2]?' ':', ')).replace(/([^,\s])$/,(!a[1]?'':'and ')+'$1')

感谢@tomsmeding提醒我,我不必强制布尔值,因为JS为我做到了。我还意识到我忘了删除将第一个三元数与串联中的串联分开的括号join()

a.join(a[2]?', ':' ').replace(/([^,\s])$/,(a[1]?'and ':'')+'$1')

我做对了吗?强制要求新高尔夫球手道歉。


1
喜欢正则表达式的人称为受虐狂。
seequ 2014年

实际上,您根本不需要!!a[2]?A:B已经工作了。可能必须再次反转布尔值。
tomsmeding

@tomsmeding-您是正确的。我一直对JavaScript的默认布尔强制行为保持警惕,因此我有一个习惯,即手动强制布尔值...
Adrian

@Adrian Correction:对于除空字符串以外的任何值,都a[i]等于true。好吧,差不多。我假设如果得到2个输入,则数组的长度为2。然后a[2]===undefinedundefined评估为false。编辑:您的编辑是我的意思:)
表示

2

高尔夫脚本-31 39 34 30

你好,世界!我是长期潜伏者,是第一次海报。这是我在Golfscript中的30字节解决方案(考虑到[1 2 3]这样的数组已经在堆栈中)。

.,3<" and ":A{~A(;\+]", "}if*

结果适用于所有测试用例。

编辑:接,CJam!


编辑以说明长度为1的数组。
Josiah Winslow 2014年

编辑为更有效的算法。
Josiah Winslow 2014年

战斗还在继续。:P
丹尼斯

Ah, but now we're even. :P
Josiah Winslow

2

Xojo, 52 71 83 chars

dim i as int8=ubound(L)
L(i)=if(i=0,"","and ")+L(i)
Return L.Join(if(i=1," ",", ")

Note that UBound is one less than the array length.


This seems to add the comma when there are 2 items - should not
edc65

Good catch. Edited to fix.
silverpie

2

Excel VBA, 108 Bytes

Anonymous VBE immediate window function that takes input as space delimited array from range A1 and outputs to the VBE immediate window.

x=Split([A1]):y=UBound(x):For i=0To y-2:?x(i)", ";:Next:If y>0Then?x(i)IIf(y>1,",","")" and "x(i+1)Else?[A1]

1

Racket 87

(define(f x)(string-join(map ~a x)", "#:before-last(if(= 2(length x))" and "", and ")))

I still find the function names in lisps to be way too long for golfing.
seequ

1

Python 62 chars

Assuming that i is the list of strings:

(" and", ", and")[len(i) < 2].join(", ".join(i).rsplit(",",1))

1

C# 102 Chars

var i=m.Count(),l=i;if(l>2)l--;var r=string.Join(", ",m.Take(l));if(l!=i)r+=" and "+m.Last();return r;

1

Julia (53)

print(join(ARGS,", ",(endof(ARGS)>2?",":"")" and "))

Takes args from STDIN and outputs to STDOUT

Solution using Base.join(items, delim[, last])

Edit:

Test cases

julia oxfordComma.jl 1

1

julia oxfordComma.jl 1 2

1 and 2

julia oxfordComma.jl 1 2 3

1, 2, and 3


1
I don't know Julia, but this looks like it doesn't generate the Oxford comma.
flornquake

@flornquake it does print with the Oxford comma, due to the optional "last" argument
Cruor

2
It should be 1, 2, and 3, not 1, 2 and 3.
flornquake

1

Rant (108)

[$[l:@b]:[r:each][s:[cmp:[rc];2;[is:different;,]]\s][before:[last:[notfirst:and\s]]][sync:;ordered][arg:b]]

Ungolfed:

[$[l:@b]:
    [r:each]                            # Repeat for each item
    [s:[cmp:[rc];2;[is:different;,]]\s] # Separate by comma if n > 2
    [before:[last:[notfirst:and\s]]]    # Insert "and" before last item
    [sync:;ordered]                     # Force forward order
    [arg:b]                             # Read list
]

Usage:

[$l:{A|B|C|D|E}]

Try it online


1

Pyth, 28

j>", "qlQ2+_t_Q+?"and "tQkeQ

Examples:

$ pyth programs/oxford.pyth <<< "['1']"
1

$ pyth programs/oxford.pyth <<< "['1','2']"
1 and 2

$ pyth programs/oxford.pyth <<< "['1','2','3']"
1, 2, and 3

I can't seem to figure out how the input should be formatted.
Dennis

@Dennis I'll add some test cases.
isaacg

I had actually tried that, but it didn't work with my version of Pyth (TypeError: can only concatenate list (not "str") to list). It works fine with the latest version.
Dennis

@Dennis Yeah, the adding to list rule was added quite recently.
isaacg

1

PHP - 72

Set up the input:

$i=[1,2,3,4,5];

And then the process:

$x=count($i)-1;if($x) {$i[$x]=" and ".$i[$x];}echo join($x>1?",":"",$i);
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.