Sejajarkan CSV

12

Gambaran:

Tugas Anda adalah mengambil input CSV dalam key=valueformat dan mengaturnya dengan cara yang lebih terorganisir (lihat di bawah).

Memasukkan:

Selalu via stdin . Rekaman akan selalu dalam bentuk berikut key=value:

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • Tidak akan ada daftar kunci yang mungkin di muka, Anda harus menemukannya di teks input.
  • Akhir input akan ditandai oleh EOF, implementasi apa pun EOFyang sesuai untuk OS Anda.

Keluaran:

Baris pertama dari output Anda akan menjadi daftar semua kunci, dalam urutan abjad (bahkan jika kunci semua angka). Setelah itu, cetak setiap catatan dalam format CSV yang sama dengan judul nomor yang sesuai, tanpa kunci yang tercantum. Jadi, untuk contoh di atas, output yang benar adalah:

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

Faq:

  • Apakah saya harus khawatir tentang input yang diformat dengan tidak benar?
    • Tidak. Program Anda dapat melakukan apa pun yang diinginkan (melemparkan pengecualian, mengabaikan, dll.) Jika input tidak diformat dengan benar, misalnya garis foo,bar,baz
  • Bagaimana cara saya menangani pelolosan karakter khusus?
    • Anda dapat berasumsi bahwa tidak akan ada tambahan ,atau =dalam data yang bukan bagian dari key=valueformat. "tidak memiliki arti khusus dalam kontes ini (meskipun dalam CSV tradisional). juga tidak istimewa dengan cara apa pun.
    • Baris harus cocok dengan regex berikut: ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • Karenanya, baik kunci dan nilai akan cocok [^=,]+
  • Bagaimana dengan CRLFvs.LF ?
    • Anda dapat memilih pembatas apa pun yang sesuai untuk platform Anda. Sebagian besar bahasa menangani ini tanpa kode pembatas khusus.
  • Apakah saya perlu mencetak koma tertinggal jika beberapa kolom terakhir tidak ada?
    • Iya. Lihat contohnya.
  • Apakah parser CSV atau alat eksternal serupa lainnya diizinkan?
    • Tidak. Anda harus mengurai data sendiri.
durron597
sumber
15
FAQ ketika belum ada yang mengajukan pertanyaan. :-)
Justin
5
@ Quincunx Jika saya bertanya pada diri sendiri pertanyaan yang diperhitungkan;)
durron597
18
Saya merasa seperti itulah cara semua FAQ bekerja.
Martin Ender
Bisakah saya memiliki tanda koma di daftar kunci dan nilai saya? Itu akan membuat kode saya jauh lebih pendek ...
PlasmaPower
@PlasmaPower Saya tidak mengerti pertanyaannya; namun, program Anda harus sama persis dengan contoh output untuk input contoh yang diberikan
durron597

Jawaban:

3

GolfScript, 64 karakter

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

Kode ini merupakan implementasi langsung dalam GolfScript, Anda dapat menguji contoh online .

Kode beranotasi:

# 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/
Howard
sumber
2

Perl 6: 119 karakter, 120 byte

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

De-golf:

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)
Mouq
sumber
2

perl, 129/121

129 byte, tidak ada saklar baris perintah:

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}

Seperti @Dennis tunjukkan di bawah, Anda bisa mendapatkan ini menjadi 120 + 1 = 121 dengan menggunakan -n:

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

Pada dasarnya, untuk setiap baris, kami membaginya dengan koma untuk mendapatkan daftar pasangan. Untuk setiap pasangan, kami membaginya dengan tanda sama dengan untuk mendapatkan kunci dan nilainya. Kami menetapkan pasangan kunci / nilai dalam% h dan hashref lokal. Yang pertama digunakan untuk menentukan daftar kunci. Yang terakhir digunakan untuk mengingat nilai untuk baris ini.

skibrianski
sumber
1
Anda dapat menyimpan beberapa karakter dengan: 1. Menggunakan -nsakelar alih-alih for(<>){...}. 2. Memisahkan [, ]daripada menggunakan chomp. 3. Menghilangkan titik koma setelah kurung keriting.
Dennis
Terima kasih @Dennis. Saya telah menerapkan 2 saran Anda yang terakhir. Saya mungkin belum memasukkan -n ke dalam campuran tetapi saya merasa seperti seorang purist yang terlalu malas untuk mengetik di teleponnya ATM :-) Juga itu akan membutuhkan blok END, tapi saya kira itu masih akan menjadi kemenangan bersih .
skibrianski
Ya, menambahkan -n hanya menghemat 3 karakter (dua poin) dengan blok END. Saya lebih suka solusi "lebih murni". Setidaknya sampai salah satu jawaban lain mendekat =)
skibrianski
Perl benar-benar membungkus while (<>) { ... }seluruh skrip, jadi tidak perlu untuk blok END. Hapus saja for(<>){di awal dan }di akhir skrip.
Dennis
3
Namun itu akan berfungsi, selama Anda menghapus }di akhir skrip, bukan yang sesuai dengan forloop. Selain itu, Anda dapat menyimpan satu char lagi dengan menggunakan baris baru yang sebenarnya \n.
Dennis
1

JavaScript ( ES5 ) 191 183 179 168 byte

Dengan asumsi kode dijalankan di spidermonkey command line:

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]})+[])

Hasil:

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

Shim ini dapat digunakan di browser untuk mensimulasikan spidermonkey's readlinedan print:

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);
};

Tidak Disatukan:

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
    );
}
nderscore
sumber
Pertanyaannya tidak mengatakan bahwa Anda harus menggunakan "stdout" - Anda dapat menggunakan alertdi tempat console.logdan menyimpan beberapa byte sehingga.
Gaurang Tandon
@ GaurangTandon Lalu, saya harus menggabungkan semua garis garis. Saya mungkin memperbarui jawaban saya untuk menggunakan baris perintah spidermonkey dan sebagai gantinya menggunakan readlinedan printuntuk stdin / out yang sebenarnya
nderscore
1

Bash + coreutils, 188 138 byte

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
}

Keluaran:

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

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

gmelakukan parsing - itu membagi input menjadi garis dan memetakan setiap baris ke daftar (key,value)pasangan. k, dengan menggabungkan semua kunci menjadi daftar dan menghapus duplikat, membuat daftar dengan semua kunci unik yang nantinya dapat saya gunakan untuk mengurutkan. Saya melakukan ini dengan membuat "Set" di dalam main( m(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")]) untuk setiap baris, dan kemudian mengambil setiap (key,value)pasangan dari suatu garis dan meletakkannya di tempatnya di dalam daftar ( foldl). Baris 1 dari contoh menghasilkan [("abc",""),("baz","quux"),("foo","bar"),("zxc","")], yang saya gabungkan menjadi satu String ( ",quux,bar,"), digabungkan dengan baris lain, dan cetak.

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

Python 2.7 - 242 byte

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)

Perhatikan bahwa lekukan lapisan kedua adalah karakter tab tunggal, bukan empat spasi seperti yang dirender SE.

Tidak Disatukan:

#!/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)
monmon bawah tanah
sumber
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=',')
aragaer
sumber
0

k4 (40? 51? 70? 46?)

ekspresi dasarnya adalah

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

ini menerima dan mengembalikan daftar string

untuk mencocokkan spec, kita bisa lakukan secara interaktif

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

yang menerima input dari stdin dan mencetak output ke stdout

untuk aplikasi mandiri yang menerima input dari pipa, kita bisa melakukan ini:

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

juga jika Anda bersedia menganggap pembungkus k-as-filter saya yang sudah ada, awq.k, sebagai alat yang dapat diterima untuk jenis puzzle ini, maka kita dapat melakukan ini:

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

yang merupakan 46 karakter atau 40, tergantung pada bagaimana Anda menghitung perselisihan kutipan shell

Aaron Davies
sumber
Lingkungan macam apa yang diperlukan untuk menjalankan ini? qperintah? Apakah awq.kditerbitkan di suatu tempat?
Digital Trauma
32-bit q sekarang tersedia sebagai freeware dari kx.com/software-download.php . (mereka dulu hanya memiliki versi uji coba terbatas waktu gratis.) hmm, sepertinya awq sebenarnya tidak diterbitkan di mana pun; saya harus melakukan sesuatu tentang itu.
Aaron Davies
0

C # - 369

(dalam 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);}

Tidak disatukan

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);
}

Uji input string

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

Keluaran

abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop
jzm
sumber
Hanya ingin tahu, ini C # jadi harus bekerja di windows, tetapi apakah itu? (Lihat pertanyaan saya CRLFvs. LFFAQ) Sayangnya saya tidak memiliki salinan Visual Studio untuk diuji.
durron597
Saya semula seharusnya menambahkan catatan itu, tetapi sekarang saya memilikinya. Ya itu berhasil. Saya sudah membuat & mengujinya di linqpad. Saya belum mengujinya di aplikasi konsol, tetapi tidak ada alasan mengapa itu tidak berhasil. Tetapi aplikasi konsol jelas akan menambahkan lebih banyak byte ke kode.
jzm