CSV'yi hizalayın


12

Genel bakış:

İşiniz CSV girişini key=valueformatta almak ve daha düzenli (aşağıya bakınız) bir şekilde sıralamaktır.

Giriş:

Her zaman stdin ile . Kayıtlar her zaman aşağıdaki biçimde olacaktır key=value:

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • Önceden olası anahtarların bir listesi olmayacak, bunları giriş metninde bulmalısınız.
  • Girişiniz, işletim sisteminiz için uygun olan EOFne olursa olsun, tarafından belirtilir EOF.

Çıktı:

Çıktınızın ilk satırı tüm tuşların alfabetik sırayla bir listesi olacaktır (tuşların tümü sayı olsa bile). Bundan sonra, her kaydı listelenen tuşlar olmadan aynı CSV formatında uygun sayı başlığını yazdırın. Dolayısıyla, yukarıdaki örnek için doğru çıktı:

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

SSS:

  • Hatalı biçimlendirilmiş girdi konusunda endişelenmem gerekiyor mu?
    • Hayır. Giriş düzgün biçimlendirilmemişse, programınız istediği her şeyi yapabilir (istisna, yoksay, vb.) foo,bar,baz
  • Kaçan özel karakterleri nasıl ele alırım?
    • Formatın parçası olmayan ekte ,veya =verilerde bulunmayacağını varsayabilirsiniz key=value. "bu yarışmada özel bir anlamı yoktur (geleneksel CSV'de de olsa). hiçbir şekilde özel değildir.
    • Satırlar aşağıdaki normal ifadeyle eşleşmelidir: ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • Bu nedenle, hem anahtarlar hem de değerler eşleşir [^=,]+
  • CRLFVs. ne olacak LF?
    • Platformunuz için uygun olan sınırlayıcıyı seçebilirsiniz. Çoğu dil bunu özel sınırlayıcı kod olmadan ele alır.
  • Son birkaç sütun yoksa sondaki virgülleri yazdırmam gerekir mi?
    • Evet. Örneğe bakın.
  • CSV ayrıştırıcılarına veya diğer benzer harici araçlara izin veriliyor mu?
    • Hayır. Verileri kendiniz ayrıştırmalısınız.

15
Henüz kimse soru sormadığında SSS. :-)
Justin

5
@Quincunx Kendime önemli bir soru
sorarsam

18
Tüm SSS'lerin bu şekilde çalıştığını hissediyorum.
Martin Ender

Anahtarlar ve değerler listemde bir virgül alabilir miyim? Kodumu çok daha kısaltır ...
PlasmaPower

@ PlazmaPower Soruyu anlamıyorum; ancak, programınız verilen örnek giriş için örnek
çıktıyla

Yanıtlar:


3

GolfScript, 64 karakter

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

Kod, GolfScript'te basit bir uygulamadır, örneği çevrimiçi olarak test edebilirsiniz .

Açıklamalı kod:

# 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 karakter, 120 bayt

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

De-golfed:

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 bayt, komut satırı anahtarı yok:

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 aşağıda belirtildiği gibi, -n kullanarak 120 + 1 = 121 elde edebilirsiniz:

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

Temel olarak, her satır için, çiftlerin listesini almak için virgülle ayrılırız. Her çift için, anahtarı ve değeri elde etmek üzere eşittir işaretine böleriz. Anahtar / değer çiftini% h ve yerel bir hashref olarak ayarladık. Birincisi, anahtar listesini belirlemek için kullanılır. İkincisi, bu satırın değerlerini hatırlamak için kullanılır.


1
Birkaç karakter kaydedebilirsiniz: 1. -nBunun yerine anahtarı kullanarak for(<>){...}. 2. [, ]Kullanmak yerine bölme chomp. 3. Kıvrımlı parantezlerden sonra noktalı virgülün çıkarılması.
Dennis

Teşekkürler @Dennis. Son 2 önerisini uyguladım. Henüz karışıma -n atmak olabilir ama onun telefon ATM yazmak için çok tembel bir safkan gibi hissediyorum :-) Ayrıca ayrıca bir END blok gerektirir, ama yine de net bir kazanç olacağını varsayalım .
skibrianski

Evet, -n eklenmesi END bloğu ile sadece 3 karakter (iki nokta) kaydeder. "Daha saf" çözümü tercih ederim. En azından diğer cevaplardan biri yaklaşana kadar =)
skibrianski

Perl tam anlamıyla while (<>) { ... }tüm betiği sarar , böylece bir END bloğuna gerek yoktur. Komut dosyasının for(<>){başında ve }sonunda kaldırmanız yeterlidir.
Dennis

3
Yine de, }senaryonun sonunda değil, senaryonun sonunda kaldırmak sürece çalışır for. Ayrıca, yerine gerçek bir satırsonu kullanarak bir karakter daha kaydedebilirsiniz \n.
Dennis

1

JavaScript ( ES5 ) 191 183 179 168 bayt

Kodun spidermonkey komut satırında çalıştırıldığı varsayılarak:

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

Sonuç:

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

Bu şim bir tarayıcıda spidermonkey'leri simüle etmek için kullanılabilir readlineve 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);
};

Ungolfed:

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

Soru, "stdout" kullanmak zorunda olduğunuzu söylemez - bunun alertyerine console.logbazı baytları kullanabilir ve kaydedebilirsiniz.
Gaurang Tandon

@GaurangTandon Sonra, tüm anahat çizgilerini birleştirmek zorunda kalacağım. Cevabımı spidermonkey komut satırını kullanmak yerine kullanmak readlineve printgerçek stdin / out için güncelleyebilirim
nderscore

1

Bash + coreutils, 188 138 bayt

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
}

Çıktı:

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

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

gayrıştırma yapıyor - girişi satırlara böler ve her satırı bir (key,value)çift listesine eşler. k, tüm anahtarları bir liste halinde birleştirerek ve kopyaları kaldırarak, daha sonra sıralama için kullanabileceğim tüm benzersiz anahtarları içeren bir liste oluşturur. Bunu her satır için main( m(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")]) içinde bir "Set" oluşturarak ve sonra her (key,value)çifti bir satırdan alıp listede ( foldl) ait olduğu yere koyuyorum . Örnek 1'den gelen satır [("abc",""),("baz","quux"),("foo","bar"),("zxc","")], tek bir String ( ",quux,bar,") halinde birleştirdiğim, diğer satırlarla birleştirdiğim ve yazdırdığım çıktıları verir.

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

0

Python 2.7-242 bayt

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)

İkinci girinti katmanının, SE gibi dört boşluk değil, tek bir sekme karakteri olduğunu unutmayın.

Ungolfed:

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

temel ifade

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

bu hem bir dizi listesini kabul eder hem de döndürür

spec maç için, biz interaktif yapabilirdi

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

stdin'den gelen girişi kabul eder ve çıktıyı stdout'a yazdırır

bir kanaldan girişi kabul eden bağımsız bir uygulama için bunu yapabiliriz:

$ 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, önceden var olan k-as-filter sarmalayıcımı, awq.k, bu tür bir bulmaca için kabul edilebilir bir araç olarak kabul etmek istiyorsanız, bunu yapabiliriz:

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

kabuk teklifi wrangling'i nasıl saydığınıza bağlı olarak 46 karakter veya 40 karakter


Bunu çalıştırmak için ne tür bir ortama ihtiyaç var? qKomut? Bir awq.kyerde yayınlanıyor mu?
Dijital Travma

32 bit q artık kx.com/software-download.php adresinden ücretsiz olarak kullanılabilir . (eskiden sadece zaman sınırlı deneme sürümüne sahiplerdi.) hmm, awq aslında hiçbir yerde yayınlanmadı gibi görünüyor; bu konuda bir şeyler yapmalıyım.
Aaron Davies

0

C # - 369

(LINQPAD içinde)

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

Ungolfed

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

Test dizesi girişi

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

Çıktı

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

Sadece merak ediyorum, bu C # yani pencerelerde çalışmalı, ama öyle mi? (Benim Bkz CRLFvs LFNe yazık ki birlikte testine Visual Studio bir kopyası yoksa SSS soru).
durron597

Başlangıçta notu eklemeliydim, ama şimdi ekledim. Evet çalışıyor. Linqpad'de yarattım ve test ettim. Konsol uygulamasında test etmedim, ancak işe yaramamasının bir nedeni yok. Ancak bir konsol uygulaması, koda daha fazla bayt ekleyecektir.
mnsr
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.