排列CSV


12

概述:

您的工作是采用key=value格式的CSV输入,并以更有条理的方式(请参见下文)将其排列起来。

输入:

始终通过stdin。记录将始终采用以下格式key=value

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • 事先没有可能的键列表,您必须在输入文本中找到它们。
  • 输入结束将通过发出信号EOF,无论EOF您的操作系统适合哪种实现。

输出:

输出的第一行将是按字母顺序排列的所有键的列表(即使键是全数字)。之后,以相同的CSV格式将每个记录打印为适当的数字标题,而不列出键。因此,对于上面的示例,正​​确的输出将是:

abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop

常问问题:

  • 我是否需要担心输入格式错误?
    • 否。如果输入的格式不正确,例如,一行 foo,bar,baz
  • 如何处理特殊字符的转义?
    • 你可以假设不会有额外的,或者=在不属于一部分的数据key=value格式。"在此比赛中没有任何特殊含义(即使在传统CSV中也没有)。也不以任何方式特别。
    • 行应与以下正则表达式匹配: ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • 因此,键和值都将匹配 [^=,]+
  • 什么CRLFLF
    • 您可以选择适合您平台的任何定界符。大多数语言无需特殊的分隔代码即可处理此问题。
  • 如果最后几列不存在,是否需要打印尾随逗号?
    • 是。参见示例。
  • 是否允许CSV解析器或其他类似的外部工具?
    • 否。您必须自己解析数据。

15
没人问问题时的常见问题。:-)
贾斯汀

5
@Quincunx如果我问自己一个很重要的问题;)
durron597

18
我觉得所有常见问题解答都是这样工作的。
Martin Ender

我的键和值列表中可以有逗号吗?这会使我的代码短很多……
PlasmaPower

@PlasmaPower我不明白这个问题;但是,您的程序必须与给定示例输入的示例输出完全匹配
durron597

Answers:


3

GolfScript,64个字符

n%{','/{'='/}%}%:I{{0=}/}%.&$:K','*n{`{{(2$=*}%''*\;}+K%','*n}I/

该代码是GolfScript中的直接实现,您可以在线测试示例。

带注释的代码:

# Split the input into lines, each line into tuples [key, value]
# and assign the result to variable I
n%{','/{'='/}%}%:I

# From each tuple take the 0'th element (i.e the key)
{{0=}/}%

# Take the unique items (.&), sort ($) and assign the result to variable K
.&$:K

# Output: join values with , and append a newline
','*n

# {...}I/: Loop over all lines of the input 
{

  # `{...}+K%: Loop over all keys and initially push the current 
  # line for each of the keys
  `{
    # stack here is [current key, current line]
    # {}%: map to all the items of the current line
    {
      # extract the key from the current item and compare
      (2$=
      # if equal keep [value], otherwise multiply with 0, i.e. discard
      *
    }%
    # join the results (may be one or zero) and drop the key
    ''*\; 
  }+K%
  # Output: join values of current line with , and append a newline
  ','*n
}I/

2

Perl 6:119个字符,120个字节

my@l=lines.map:{/[(\w+)\=(\w+)]+%\,/;push $!,~«@0;$%(@0 Z=>@1)}
say .join(",") for$!.=sort.=uniq,($(.{@$!}X//"") for@l)

脱胶

my@l=lines.map: {
    # Parse the key=value pairs,
    # put all the keys in $/[0] (or $0)
    # put all the values in $/[1] (or $1)
    / [ (\w+) \= (\w+) ]+ % \, /;

    # Push all the keys into $!
    # (@0 just means @$0 or $/[0].list)
    push $!, ~«@0;

    # Return a hash of keys zipped into pairs with the values
    $%( @0 Z=> @1 )
}

$!.=sort.=uniq;
# …i.e., $! = $!.sort.uniq;

# Print the CSV for the keys ($!),
# followed by the CSVs for the hashes we made for each line,
# as accessed by our sorted key list. (… .{@$!} …)
# If the value doesn't exist, just use "" instead. (… X// "" …)
say .join(",") for $!, ($( .{@$!} X// "" ) for @l)

2

perl,129/121年

129字节,无命令行开关:

for(<>){push@x,{%g=map{split/=/}split/[,
]/};@h{keys%g}=()}@k=sort keys%h;$"=",";sub P{print"@_
"}P@k;for$x(@x){P map{$$x{$_}}@k}

正如@Dennis指出的那样,您可以使用-n将其设置为120 + 1 = 121:

push@x,{%g=map{split/=/}split/[,
]/};@h{keys%g}=()}@k=sort keys%h;$"=",";sub P{print"@_
"}P@k;for$x(@x){P map{$$x{$_}}@k

基本上,对于每一行,我们都按逗号分隔以获取对列表。对于每对,我们用等号分开以获得键和值。我们在%h和本地hashref中设置键/值对。前者用于确定键列表。后者用于记住该行的值。


1
您可以通过以下方式保存一些字符:1.使用-n开关代替for(<>){...}。2.拆分[, ]而不是使用chomp。3.在花括号后省略分号。
丹尼斯

谢谢@丹尼斯。我已经落实了您的建议中的后两个。我可能还没有加入-n,但是我觉得自己像个纯粹主义者,太懒了,无法在他的电话ATM上打字:-)同样,这需要一个END块,但我想那仍然是一场净赢。
skibrianski 2014年

是的,加上-n只会在END块中节省3个字符(两点)。我更喜欢“纯”的解决方案。至少直到其他答案之一更接近=)
skibrianski 2014年

Perl从字面上包裹while (<>) { ... }了整个脚本,因此不需要END块。只需删除脚本for(<>){开头和}结尾即可。
丹尼斯

3
但是,只要您删除}脚本末尾的,而不是删除与for循环对应的脚本,它将仍然有效。另外,您可以使用实际的换行符代替来保存一个字符\n
丹尼斯

1

的JavaScript(ES5191 183 179 168字节

假设代码在spidermonkey命令行中运行:

for(b=[a={}];l=readline(i=0);b.push(c))for(c={},d=l.split(/,|=/);e=d[i++];)c[a[e]=e]=d[i++];for(;c=b[i++];)print(Object.keys(a).sort().map(function(x){return c[x]})+[])

结果:

> js test.js < input.txt
abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop

可以在浏览器中使用此填充程序来模拟Spidermonkey readlineprint

var I = 0, LINES = '\
foo=bar,baz=quux\n\
abc=123,foo=fubar\n\
baz=qwe,abc=rty,zxc=uiop,foo=asdf'.split('\n'),
readline = function(){
    return LINES[I++];
}, print = function(){
    return console.log.apply(console, arguments);
};

取消高尔夫:

a = {};                        // this object holds all keys found
b = [a];                       // array key:value pairs of each line, initialized with our key holder object in position 0
for(;l = readline();){         // store each line in l, loop until blank/undefined line
    c = {};                    // create a new object for this line's key:value pairs
    d = l.split(/,|=/);        // split line by commas and equals
    for(i = 0; e = d[i++];){   // loop through each key
        a[e] = e;              // set the key=key for key holder object
        c[e] = d[i++];         // set key=value for the line object
    }
    b.push(c);                 // push line object onto array
}
for(i = 0; c = b[i++];){       // loop through all line objects until undefined
    print(                     // print line
        Object.keys(a).sort(). // get sorted list of keys
        map(function(x){
            return c[x]        // map values from line object
        })
        + []                   // cast array to string
    );
}

问题并没有说明您必须使用“ stdout”-可以alert代替console.log并保存一些字节。
Gaurang Tandon 2014年

@GaurangTandon然后,我必须连接所有轮廓线。我可能会更新我的答案以使用Spidermonkey命令行,而是使用readlineprint进行实际的stdin / out
nderscore 2014年

1

Bash + coreutils,188138字节

p=paste\ -sd,
f=`cat`
h=`tr , '\n'<<<$f|cut -d= -f1|sort -u`
$p<<<"$h"
for l in $f;{
join -o2.2 -a1 - <(tr =, ' \n'<<<$l|sort)<<<"$h"|$p
}

输出:

$ ./lineupcsv.sh < input.csv 
abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop
$ 

0

哈斯克尔,357 334

import Data.List
o=1<2
s u|u==""=""|o=tail u
t=takeWhile
d=dropWhile
c=(/=',')
e=(/='=')
p x|x/=""=Just((t e x,t c.s.d e$x),s.d c$x)|o=Nothing
g=m(unfoldr p).lines
k=nub.sort.(m fst=<<).g
[]#_=[]
(t@(x,u):z)#n@(a,b)|x==a=n:z|o=t:z#n
i=intercalate
main=interact$ \d->i"\n"$(i","$k d):m(i",".m snd.foldl(#)(m(flip(,)"").k$d))(g d)
m=map

g在进行解析-将输入分成几行,并将每行映射到(key,value)成对的列表。k通过将所有键串联到列表中并删除重复项,创建了一个包含所有唯一键的列表,以后可以将其用于排序。为此,我在mainm(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")])中为每一行创建了一个“集合” ,然后(key,value)从一行中取出每一对,并将其放在列表中的位置(foldl)。示例中的第1行yields [("abc",""),("baz","quux"),("foo","bar"),("zxc","")],我将其连接为单个String(",quux,bar,"),与其他行连接并进行打印。

>>> csv.exe < input.txt
abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop

0

Python 2.7-242字节

的Bleh

import os
c=[r.split(',')for r in os.read(0,99).split('\n')]
k=sorted(list(set(sum([[s.split('=')[0]for s in r]for r in c],[]))))
print','.join(k)
for l in c:
 t=[''for i in k]
 for s in l:
    o,v=s.split('=')
    t[k.index(o)]=v
 print','.join(t)

请注意,缩进的第二层是单个制表符,而不是像SE这样的四个空格。

取消高尔夫:

#!/bin/python2

import os

# I do input as a list comprehension in the original but this is equivalent
c = []

# For each line in the input
for r in os.read(0,99).split('\n'):
    # Add a list of key=value pairs in that row to c
    c.append(r.split(','))

# Another thing done as a list comprehension, but I'll space it out
k = []

# For each list of key=value pair s in c
for r in c:
    # For each actual key=value pair in that list
    for s in r:
        # Get the key
        k.append(s.split('=')[0])

# Discard dupes by converting to set and back, then sort
k = sorted(list(set(k)))

# Seperate these keys by commas, then print
print ','.join(k)

# For each line in c
for l in c:
    # t has one empty string for each key in the input
    t = ['' for i in k]
    # For each key=value pair in the line
    for s in l:
        # o = key, v = value
        o, v = s.split('=')
        # Find the position that the key is in the list of keys, then put the
        # value in t at that position
        t[k.index(o)] = v

    # Now each value is in the right position and the keys with no values on this
    # line have an empty string. Join everything with commas and print
    print ','.join(t)

0

Python 3: 200 195 192 189 187

import sys
r=[dict(p.split('=')for p in l[:-1].split(','))for l in sys.stdin]
x=set()
for d in r:x|=d.keys()
k=sorted(x)
for l in[k]+[[r.get(k,'')for k in k]for r in r]:print(*l,sep=',')

0

k4(40?51?70?46?)

基本表达是

","0:{(x@<x:?,/?!:'x)#/:x}(!).'"S=,"0:/:

这既接受并返回字符串列表

为了符合规格,我们可以互动地进行

-1","0:{(x@<x:?,/?!:'x)#/:x}(!).'"S=,"0:/:."\\cat";

接受来自stdin的输入并将输出打印到stdout

对于接受管道输入的独立应用程序,我们可以这样做:

$ cat i.k
.z.pi:{t,:`\:x}
.z.exit:{-1","0:{(x@<x:?,/?!:'x)#/:x}(!).'"S=,"0:/:t}
$ cat i.txt|q i.k
abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop
$ 

而且,如果您愿意将我之前存在的k-as-filter包装器awq.k视为此类难题的可接受工具,那么我们可以这样做:

$ cat i.txt|awq.k '","0:{(x@<x:?,/?!:'\''x)#/:x}(!).'\''"S=,"0:/:'

这是46个字符还是40个字符,具体取决于您如何计算shell引号争用


需要哪种环境才能运行此环境? q命令?在awq.k某处发表?
Digital Trauma 2014年

现在可以从kx.com/software-download.php免费获得32位q 。(它们以前只是免费提供有时间限制的试用版。)嗯,看来awq实际上没有在任何地方发布;我应该为此做些事情。
亚伦·戴维斯

0

C#-369

(在LINQPAD中)

void C(string a){var k=a.Split(new[]{',','\n'}).Select(s=>s.Split('=')[0]).OrderBy(o=>o).Distinct();var t=string.Join(",", k)+"\n";foreach(var x in a.Split('\n')){for(int i=0;i<k.Count();i++){foreach(var y in x.Split(',').OrderBy(o=>o.Split('=')[0]))if(k.ElementAt(i)==y.Split('=')[0])t+=y.Split('=')[1];t+=",";}t=t.Remove(t.LastIndexOf(','),1)+"\n";}Console.Write(t);}

不打高尔夫球

void C(string a)
{
    var k=a.Split(new[]{',','\n'}).Select(s=>s.Split('=')[0]).OrderBy(o=>o).Distinct();
    var t=string.Join(",", k)+"\n";
    foreach(var x in a.Split('\n'))
    {
        for(int i=0;i<k.Count();i++)
        {
            foreach(var y in x.Split(',').OrderBy(o=>o.Split('=')[0]))
                if(k.ElementAt(i)==y.Split('=')[0])
                    t+=y.Split('=')[1];
            t+=",";
        }
        t=t.Remove(t.LastIndexOf(','),1)+"\n";
    }
    Console.Write(t);
}

测试字符串输入

C("foo=bar,baz=quux\nabc=123,foo=fubar\nbaz=qwe,abc=rty,zxc=uiop,foo=asdf");

输出量

abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop

只是好奇,这是C#,所以它应该在Windows中工作,但是吗?(请参阅我的CRLFvs. LFFAQ问题。)不幸的是,我没有可供测试的Visual Studio副本。
durron597

我本来应该添加注释,但是现在有了。是的,它有效。我已经在linqpad中创建并测试了它。我尚未在控制台应用程序中对其进行测试,但是没有任何理由不起作用。但是控制台应用程序显然会向代码中添加更多字节。
jzm 2014年
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.