CSV 정렬


12

개요 :

귀하의 임무는 CSV 입력을 형식적으로 취하여 key=value보다 체계적인 방식으로 정리하는 것입니다 (아래 참조).

입력:

항상 stdin을 통해 . 기록은 항상 다음과 같은 형식입니다 key=value.

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • 사전에 가능한 키 목록이 없으므로 입력 텍스트에서 찾아야합니다.
  • OS에 적합한 EOF구현이 무엇이든 입력 끝은에 의해 알립니다 EOF.

산출:

출력의 첫 번째 행은 모든 키의 목록이 알파벳순으로 정렬됩니다 (키가 모두 숫자 인 경우에도). 그런 다음 키를 나열하지 않고 각 레코드를 동일한 CSV 형식으로 해당 번호 제목으로 인쇄하십시오. 따라서 위의 예에서 올바른 출력은 다음과 같습니다.

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

자주하는 질문:

  • 형식이 잘못된 입력에 대해 걱정해야합니까?
    • 아니요. 입력 형식이 올바르지 않으면 프로그램에서 원하는 것을 수행 할 수 있습니다 (예외 발생, 무시 등). foo,bar,baz
  • 특수 문자 이스케이프 처리는 어떻게합니까?
    • 형식의 일부가 아닌 추가 ,또는 =데이터가 없다고 가정 할 수 있습니다 key=value. "이 컨테스트에는 특별한 의미가 없습니다 (전통적인 CSV에서도 마찬가지 임). 어떤 식 으로든 특별하지 않습니다.
    • 줄은 다음 정규식과 일치해야합니다. ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • 따라서 키와 값이 모두 일치합니다 [^=,]+
  • 무엇에 대한 CRLFLF?
    • 플랫폼에 적합한 구분 기호를 선택할 수 있습니다. 대부분의 언어는 특별한 구분 코드없이 이것을 처리합니다.
  • 마지막 몇 개의 열이 없으면 후미 쉼표를 인쇄해야합니까?
    • 예. 예를 참조하십시오.
  • CSV 파서 또는 기타 유사한 외부 도구가 허용됩니까?
    • 아니요. 데이터를 직접 파싱해야합니다.

15
아직 아무도 질문하지 않은 경우 FAQ. :-)
저스틴

5
@Quincunx 내가 스스로에게 중요한 질문을하면;)
durron597

18
모든 FAQ가 작동하는 느낌이 있습니다.
Martin Ender

키 및 값 목록에 후행 쉼표를 사용할 수 있습니까? 내 코드가 훨씬 짧아 질 것입니다 ...
PlasmaPower

@PlasmaPower 나는 질문을 이해하지 못한다; 그러나 프로그램은 주어진 예제 입력에 대한 예제 출력과 정확히 일치해야합니다.
durron597

답변:


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

펄, 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 및 로컬 해시 참조로 설정했습니다. 전자는 키 목록을 결정하는 데 사용됩니다. 후자는이 줄의 값을 기억하는 데 사용됩니다.


1
다음과 같은 방법으로 몇 개의 문자를 저장할 수 있습니다. 1. -n대신 스위치를 사용하십시오 for(<>){...}. [, ]을 사용하지 않고 분할합니다 chomp. 3. 중괄호 뒤에 세미콜론을 생략하십시오.
Dennis

감사합니다 @Dennis. 귀하의 제안 중 후자 2를 구현했습니다. 나는 아직 믹스에 -n을 던질 수도 있지만 전화 ATM에 입력하기에는 너무 게으른 순수 주의자처럼 느낍니다. .
skibrianski

예, -n을 추가하면 END 블록으로 3 자 (2 포인트) 만 저장됩니다. 나는 "순수한"솔루션을 선호합니다. 적어도 다른 답변 중 하나가 가까워 질 때까지 =)
skibrianski

Perl은 문자 그대로 while (<>) { ... }전체 스크립트를 감싸 므로 END 블록이 필요하지 않습니다. 스크립트 for(<>){의 시작과 }끝에서 제거하십시오 .
Dennis

3
그럼에도 불구하고 }스크립트 끝에있는 for루프 를 제거 하는 스크립트가 아닌 스크립트의 끝 을 제거하는 한 작동 합니다. 또한 대신에 실제 줄 바꿈을 사용하여 하나 이상의 문자를 저장할 수 있습니다 \n.
Dennis

1

자바 스크립트 ( ES5 ) 191 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

@GaurangTandon 그런 다음 모든 윤곽선을 연결해야합니다. 나는 SpiderMonkey를 명령 줄을 사용하는 대신 사용하는 내 대답을 업데이트 할 수 있습니다 readlineprint실제 표준 입력을위한 / 아웃
nderscore

1

배쉬 +로 coreutils, 188 138 바이트

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, 모든 키를 목록에 연결하고 중복을 제거하면 나중에 정렬에 사용할 수있는 모든 고유 키가 포함 된 목록을 만듭니다. 각 줄에 대해 main( m(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")]) 안에 "Set"을 만든 다음 줄에서 모든 (key,value)쌍 을 가져 와서 목록 ( foldl)에 속하는 위치에 놓습니다 . 예제의 1 행은 yield입니다 [("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

파이썬 2.7-242 바이트

eh

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와 같이 4 개의 공백이 렌더링되지 않습니다.

언 골프 드 :

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

파이썬 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
$ 

altho 기존 k-as-filter 래퍼 awq.k를 이러한 종류의 퍼즐에 적합한 도구로 고려하고 싶다면 다음과 같이하십시오.

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

쉘 따옴표를 계산하는 방법에 따라 46 자 또는 40 자입니다.


이것을 실행하려면 어떤 환경이 필요합니까? q명령? 인가 awq.k어딘가에 게시?
Digital Trauma

32 비트 q는 이제 kx.com/software-download.php 에서 프리웨어로 제공됩니다 . (시간 제한 시험판 만 무료로 사용 했었습니다.) 흠, awq가 실제로 어디에도 게시되지 않은 것 같습니다. 나는 그것에 대해 뭔가를해야합니다.
Aaron Davies

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에서 작동해야하지만 그렇지 않습니까? (내 질문 CRLFLFFAQ 질문 참조 ) 불행히도 테스트 할 Visual Studio 사본이 없습니다.
durron597

나는 원래 메모를 추가 했어야하지만 지금은 가지고 있습니다. 그렇습니다. linqpad에서 생성하고 테스트했습니다. 콘솔 앱에서 테스트하지는 않았지만 작동하지 않는 이유는 없습니다. 그러나 콘솔 앱은 분명히 더 많은 바이트를 코드에 추가합니다.
jzm
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.