Richten Sie die CSV aus

12

Überblick:

Ihre Aufgabe ist es, CSV-Eingaben in einem key=valueFormat zu erfassen und besser zu organisieren (siehe unten).

Eingang:

Immer über stdin . Aufzeichnungen werden immer in der folgenden Form vorliegen key=value:

foo=bar,baz=quux
abc=123,foo=fubar
baz=qwe,abc=rty,zxc=uiop,foo=asdf
  • Es wird keine Liste möglicher Schlüssel im Voraus geben, Sie müssen sie im Eingabetext finden.
  • Das Ende der Eingabe wird angezeigt EOF, je nachdem, welche Implementierung EOFfür Ihr Betriebssystem geeignet ist.

Ausgabe:

In der ersten Zeile Ihrer Ausgabe werden alle Tasten in alphabetischer Reihenfolge aufgelistet (auch wenn es sich bei allen Tasten um Zahlen handelt). Drucken Sie danach jeden Datensatz im selben CSV-Format mit der entsprechenden Nummernüberschrift aus, ohne die aufgelisteten Schlüssel. Für das obige Beispiel wäre die richtige Ausgabe also:

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

FAQ:

  • Muss ich mir über falsch formatierte Eingaben Sorgen machen?
    • Nein. Ihr Programm kann tun, was es will (eine Ausnahme auslösen, ignorieren usw.), wenn die Eingabe nicht korrekt formatiert ist, z. B. eine Zeile von foo,bar,baz
  • Wie gehe ich mit Sonderzeichen um?
    • Sie können davon ausgehen, dass es keine zusätzlichen ,oder =in den Daten, die nicht Teil des key=valueFormats sind. "hat in diesem Wettbewerb keine besondere Bedeutung (obwohl dies in der traditionellen CSV-Version der Fall ist). ist auch in keiner Weise speziell.
    • Zeilen sollten mit dem folgenden regulären Ausdruck übereinstimmen: ^([^=,]+=[^=,]+)(,[^=,]+=[^=,]+)*$
      • Daher stimmen sowohl Schlüssel als auch Werte überein [^=,]+
  • Was ist CRLFgegen LF?
    • Sie können das für Ihre Plattform geeignete Trennzeichen auswählen. Die meisten Sprachen behandeln dies ohne speziellen Begrenzungscode.
  • Muss ich nachstehende Kommas ausgeben, wenn die letzten Spalten nicht vorhanden sind?
    • Ja. Siehe das Beispiel.
  • Sind CSV-Parser oder ähnliche externe Tools zulässig?
    • Sie müssen die Daten selbst analysieren.
durron597
quelle
15
FAQ, wenn noch niemand Fragen gestellt hat. :-)
Justin
5
@ Quincunx Wenn ich mir die Frage stelle, die zählt;)
Durron597
18
Ich habe das Gefühl, dass alle FAQs so funktionieren.
Martin Ender
Kann ich in meiner Liste der Schlüssel und Werte ein nachgestelltes Komma verwenden? Es würde meinen Code viel kürzer machen ...
PlasmaPower
@PlasmaPower Ich verstehe die Frage nicht. Ihr Programm muss jedoch genau mit der Beispielausgabe für die angegebene Beispieleingabe
übereinstimmen

Antworten:

3

GolfScript, 64 Zeichen

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

Der Code ist eine einfache Implementierung in GolfScript. Sie können das Beispiel testen online .

Kommentierter Code:

# 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
quelle
2

Perl 6: 119 Zeichen, 120 Bytes

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

Entgolft:

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
quelle
2

perl, 129/121

129 Bytes, keine Befehlszeilenoptionen:

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}

Wie @Dennis unten ausführt, können Sie dies mit -n auf 120 + 1 = 121 bringen:

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

Grundsätzlich werden wir für jede Zeile durch Kommas getrennt, um die Liste der Paare zu erhalten. Für jedes Paar teilen wir durch das Gleichheitszeichen, um den Schlüssel und den Wert zu erhalten. Wir setzen das Schlüssel / Wert-Paar in% h und eine lokale Hashref. Ersteres wird verwendet, um die Liste der Schlüssel zu bestimmen. Letzteres wird verwendet, um die Werte für diese Zeile zu speichern.

Skibrianski
quelle
1
Sie können ein paar Zeichen speichern, indem Sie: 1. den -nSchalter anstelle von verwenden for(<>){...}. 2. Herumspalten [, ]statt benutzen chomp. 3. Lassen Sie das Semikolon hinter den geschweiften Klammern weg.
Dennis
Danke @Dennis. Ich habe die letzten 2 Ihrer Vorschläge umgesetzt. Ich kann mich noch in die Mischung einmischen, aber ich fühle mich wie ein Purist, der zu faul ist, um an seinem Telefon-Geldautomaten zu tippen :-) Auch das würde einen END-Block erfordern, aber ich nehme an, es wäre immer noch ein Nettogewinn .
Skibrianski
Ja, das Hinzufügen von -n spart nur 3 Zeichen (zwei Punkte) mit dem END-Block. Ich bevorzuge die "reinere" Lösung. Zumindest bis eine der anderen Antworten näher kommt =)
skibrianski
Perl umschließt buchstäblich while (<>) { ... }das gesamte Skript, sodass kein END-Block erforderlich ist. Einfach for(<>){am Anfang und }am Ende des Skripts entfernen .
Dennis
3
Es wird trotzdem funktionieren, solange Sie das }am Ende des Skripts entfernen , nicht das, das der forSchleife entspricht. Sie können auch ein Zeichen mehr sparen, indem Sie stattdessen eine aktuelle Zeile eingeben \n.
Dennis
1

JavaScript ( ES5 ) 191 183 179 168 Bytes

Angenommen, der Code wird in der spidermonkey-Befehlszeile ausgeführt:

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

Ergebnis:

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

Dieses Shim kann in einem Browser verwendet werden, um Spidermonkeys zu simulieren readlineund 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
    );
}
nderscore
quelle
Die Frage sagen nicht , dass Sie „stdout“ verwenden - Sie können alertanstelle von console.logund speichern einige somit Bytes.
Gaurang Tandon
@ GaurangTandon Dann müsste ich alle Gliederungslinien verketten. Ich könnte meine Antwort zu verwenden Spiderbefehlszeile aktualisieren und stattdessen verwenden readlineund printfür die tatsächliche stdin / out
nderscore
1

Bash + Coreutils, 188 138 Bytes

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
}

Ausgabe:

$ ./lineupcsv.sh < input.csv 
abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop
$ 
Digitales Trauma
quelle
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

gParsing - Teilt die Eingabe in Zeilen und ordnet jede Zeile einer Liste von (key,value)Paaren zu. kDurch Zusammenfügen aller Schlüssel zu einer Liste und Entfernen von Duplikaten wird eine Liste mit allen eindeutigen Schlüsseln erstellt, die ich später zum Sortieren verwenden kann. Dazu erstelle ich für jede Zeile ein "Set" inside main( m(flip(,)"").k$d == [("abc",""),("baz",""),("foo",""),("zxc","")]) und nehme dann jedes (key,value)Paar aus einer Zeile und setze es dort, wo es in der Liste hingehört ( foldl). Zeile 1 aus dem Beispiel ergibt [("abc",""),("baz","quux"),("foo","bar"),("zxc","")], was ich zu einem einzelnen String ( ",quux,bar,") verkettete, mit den anderen Zeilen verkettete und drucke.

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

Python 2.7 - 242 Bytes

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)

Beachten Sie, dass die zweite Ebene der Einrückung ein einzelnes Tabulatorzeichen ist und nicht vier Leerzeichen, wie sie SE darstellt.

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)
untergrundbahn
quelle
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
quelle
0

k4 (40 & le; 51 & le; 70 & le; 46 & le;)

der Grundausdruck ist

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

Dadurch wird eine Liste von Zeichenfolgen akzeptiert und zurückgegeben

Um der Spezifikation zu entsprechen, könnten wir dies interaktiv tun

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

Dieser akzeptiert die Eingabe von stdin und druckt die Ausgabe nach stdout

Für eine eigenständige App, die Eingaben von einer Pipe akzeptiert, könnten wir dies tun:

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

Auch wenn Sie bereit sind, meinen bereits vorhandenen k-as-Filter-Wrapper awq.k als akzeptables Werkzeug für diese Art von Rätsel zu betrachten, können wir dies tun:

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

Das sind entweder 46 Zeichen oder 40, je nachdem, wie Sie das Zitat-Wrangling in der Shell zählen

Aaron Davies
quelle
Welche Umgebung wird benötigt, um dies auszuführen? qBefehl? Wird awq.kirgendwo veröffentlicht?
Digital Trauma
32-bit q ist ab sofort als Freeware von erhältlich kx.com/software-download.php verfügbar . (Früher hatten sie nur eine zeitlich begrenzte kostenlose Testversion.) Hmm, es sieht so aus, als ob awq nirgendwo veröffentlicht wird. Ich sollte etwas dagegen tun.
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);
}

String Eingabe testen

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

Ausgabe

abc,baz,foo,zxc
,quux,bar,
123,,fubar,
rty,qwe,asdf,uiop
jzm
quelle
Nur neugierig, das ist C #, also sollte es in Windows funktionieren, aber ist es das? (Siehe meine CRLFvs. LFFAQ-Frage) Leider habe ich keine Kopie von Visual Studio zum Testen.
Durron597
Eigentlich hätte ich die Notiz hinzufügen sollen, aber ich habe sie jetzt. Ja es funktioniert. Ich habe es in Linqpad erstellt und getestet. Ich habe es nicht in der Konsolen-App getestet, aber es gibt keinen Grund, warum es nicht funktionieren würde. Aber eine Konsolen-App würde dem Code offensichtlich mehr Bytes hinzufügen.
JZM