Allinea il CSV


12

Panoramica:

Il tuo compito è prendere l'input CSV in key=valueformato e allinearlo in un modo più organizzato (vedi sotto).

Ingresso:

Sempre tramite stdin . I record saranno sempre nella seguente forma key=value:

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • Non ci sarà un elenco di possibili chiavi in ​​anticipo, è necessario trovarle nel testo di input.
  • La fine dell'input verrà segnalata da EOF, qualunque sia l'implementazione EOFappropriata per il tuo sistema operativo.

Produzione:

La prima riga dell'output sarà un elenco di tutti i tasti, in ordine alfabetico (anche se i tasti sono tutti numeri). Successivamente, stampa ogni record nello stesso formato CSV con l'intestazione del numero appropriato, senza le chiavi elencate. Quindi, per l'esempio sopra, l'output corretto sarebbe:

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

FAQ:

  • Devo preoccuparmi di input formattati in modo errato?
    • No. Il tuo programma può fare quello che vuole (generare un'eccezione, ignorare, ecc.) Se l'input non è formattato correttamente, ad esempio una riga di foo,bar,baz
  • Come gestisco i caratteri speciali di escape?
    • Si può presumere che non vi saranno dati aggiuntivi ,o =nei dati che non fanno parte del key=valueformato. "non ha alcun significato speciale in questo concorso (anche se lo fa nel CSV tradizionale). non è nemmeno speciale in alcun modo.
    • Le righe devono corrispondere alla seguente regex: ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • Pertanto, sia le chiavi che i valori corrisponderanno [^=,]+
  • Che dire di CRLFvs. LF?
    • Puoi scegliere qualsiasi delimitatore appropriato per la tua piattaforma. La maggior parte delle lingue lo gestisce senza uno speciale codice di delimitazione.
  • Devo stampare le virgole finali se le ultime colonne non esistono?
    • Sì. Vedi l'esempio
  • Sono consentiti parser CSV o altri strumenti esterni simili?
    • No. È necessario analizzare i dati da soli.

15
FAQ quando nessuno ha ancora posto domande. :-)
Justin

5
@Quincunx Se mi pongo la domanda che conta;)
durron597,

18
Ho la sensazione che sia così che funzionano tutte le FAQ.
Martin Ender,

Posso avere una virgola finale nel mio elenco di chiavi e valori?
Renderebbe il

@PlasmaPower Non capisco la domanda; tuttavia, il programma deve corrispondere esattamente all'output di esempio per l'input di esempio fornito
durron597

Risposte:


3

GolfScript, 64 caratteri

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

Il codice è un'implementazione diretta in GolfScript, è possibile testare l'esempio online .

Codice annotato:

# 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 caratteri, 120 byte

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

De-giocato a 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)

2

perl, 129/121

129 byte, nessuna opzione della riga di comando:

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}

Come indicato da @Dennis di seguito, puoi ottenere questo a 120 + 1 = 121 usando -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

Fondamentalmente, per ogni riga, abbiamo diviso le virgole per ottenere l'elenco delle coppie. Per ogni coppia, abbiamo diviso per il segno di uguale per ottenere la chiave e il valore. Impostiamo la coppia chiave / valore in% h e un hashref locale. Il primo viene utilizzato per determinare l'elenco di chiavi. Quest'ultimo è usato per ricordare i valori per questa riga.


1
È possibile salvare alcuni caratteri: 1. Utilizzando l' -nopzione anziché for(<>){...}. 2. Dividi [, ]invece di usare chomp. 3. Omettere il punto e virgola dopo le parentesi graffe.
Dennis,

Grazie @Dennis. Ho implementato gli ultimi 2 dei tuoi suggerimenti. Potrei ancora buttarmi nel mix, ma mi sento come un purista che è troppo pigro per scrivere sul suo bancomat del telefono :-) Anche questo richiederebbe un blocco END, ma suppongo che sarebbe comunque una vittoria netta .
skibrianski,

Sì, l'aggiunta di -n salva solo 3 caratteri (due punti) con il blocco END. Preferisco la soluzione "più pura". Almeno fino a quando una delle altre risposte non si avvicina =)
skibrianski,

Perl avvolge letteralmente while (<>) { ... }l'intero script, quindi non è necessario un blocco END. Rimuovi for(<>){all'inizio e }alla fine dello script.
Dennis,

3
Funzionerà comunque, purché rimuova }la fine dello script, non quella corrispondente al forciclo. Inoltre, puoi salvare un altro carattere utilizzando una nuova riga effettiva anziché \n.
Dennis,

1

JavaScript ( ES5 ) 191 183 179 168 byte

Supponendo che il codice venga eseguito nella riga di comando di 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]})+[])

Risultato:

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

Questo spessore può essere utilizzato in un browser per simulare spidermonkey readlinee 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
    );
}

La domanda non dice che devi usare "stdout" - puoi usare alertal posto di console.loge salvare alcuni byte in questo modo.
Gaurang Tandon,

@GaurangTandon Quindi, dovrei concatenare tutte le linee di contorno. Potrei aggiornare la mia risposta per usare la riga di comando di spidermonkey e invece usare readlinee printper stdin / out effettivi
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
}

Produzione:

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

gsta eseguendo l'analisi: suddivide l'input in righe e mappa ciascuna riga in un elenco di (key,value)coppie. k, concatenando tutte le chiavi in ​​un elenco e rimuovendo i duplicati, crea un elenco con tutte le chiavi univoche che posso utilizzare in seguito per l'ordinamento. Lo faccio creando un "Set" dentro main( m(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")]) per ogni riga, quindi prendendo ogni (key,value)coppia da una linea e inserendola nel punto in cui appartiene alla lista ( foldl). La riga 1 dell'esempio produce [("abc",""),("baz","quux"),("foo","bar"),("zxc","")], che concateno in una singola stringa ( ",quux,bar,"), concatena con le altre linee e stampa.

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

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)

Si noti che il secondo livello di rientro è un singolo carattere di tabulazione, non quattro spazi come SE lo rende.

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?)

l'espressione di base è

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

questo accetta e restituisce un elenco di stringhe

per abbinare le specifiche, potremmo fare interattivamente

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

che accetta l'input da stdin e stampa l'output su stdout

per un'app standalone che accetta input da una pipe, potremmo farlo:

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

anche se sei disposto a considerare il mio wrapper k-as-filter pre-esistente, awq.k, come uno strumento accettabile per questo tipo di puzzle, allora possiamo farlo:

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

che è composto da 46 caratteri o 40, a seconda di come si contano le quotazioni della shell


Che tipo di ambiente è necessario per eseguire questo? qcomando? È awq.kpubblicato da qualche parte?
Trauma digitale

32-bit q è ora disponibile come freeware da kx.com/software-download.php . (avevano una versione di prova gratuita limitata nel tempo.) hmm, sembra che awq non sia effettivamente pubblicato da nessuna parte; dovrei fare qualcosa al riguardo.
Aaron Davies,

0

C # - 369

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

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 input stringa

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

Produzione

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

Solo curioso, questo è C # quindi dovrebbe funzionare in Windows, ma lo fa? (Vedi la mia domanda CRLFvs. LFFAQ) Sfortunatamente non ho una copia di Visual Studio con cui provare.
durron597,

Inizialmente avrei dovuto aggiungere la nota, ma ora ho. Sì funziona. L'ho creato e testato in linqpad. Non l'ho testato nell'app per console, ma non c'è motivo per cui non funzioni. Ma un'app console ovviamente aggiungerebbe più byte al codice.
jzm
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.