Oneliner zum Zusammenführen von Zeilen mit demselben ersten Feld

15

Dies ist meine erste Codegolf-Frage, daher entschuldige ich mich im Voraus, wenn dies nicht angemessen ist, und freue mich über jegliches Feedback.

Ich habe eine Datei mit diesem Format:

a | rest of first line
b | rest of second line
b | rest of third line
c | rest of fourth line
d | rest of fifth line
d | rest of sixth line

Der tatsächliche Inhalt variiert, ebenso wie das Trennzeichen. Der Inhalt ist nur Text. Das Trennzeichen wird nur einmal pro Zeile angezeigt. Für dieses Puzzle können Sie das Trennzeichen ändern, z. B. "%" als Trennzeichen verwenden.

Gewünschte Ausgabe:

a | rest of first line
b | rest of second line % rest of third line
c | rest of fourth line
d | rest of fifth line % rest of sixth line

Ich habe bereits Ruby- und Awk-Skripte, um dies zusammenzuführen, aber ich vermute, dass es möglich ist, einen kurzen Oneliner zu haben. dh ein Einzeiler, der zusammen mit Pipes und anderen Befehlen in der Befehlszeile verwendet werden kann. Ich kann es nicht herausfinden, und mein eigenes Skript ist zu lang, um es nur in der Befehlszeile zu komprimieren.

Kürzeste Zeichen bevorzugt. Die Eingabe muss nicht unbedingt sortiert sein, sondern es geht uns nur darum, aufeinanderfolgende Zeilen mit übereinstimmenden ersten Feldern zusammenzuführen. Es gibt unbegrenzte Zeilen mit übereinstimmenden ersten Feldern. Feld 1 kann alles sein, z. B. Namen von Früchten, Eigennamen usw.

(Ich laufe auf MacOS, daher bin ich persönlich am meisten an Implementierungen interessiert, die auf dem Mac laufen).


Hier ist ein zweites Beispiel / Test. Hinweis "|" ist das Trennzeichen. Der Raum vor dem "|" ist irrelevant, und wenn erneut gesendet werden sollte als Teil des Schlüssels. Ich verwende "%" als Begrenzungszeichen in der Ausgabe, kann aber auch hier das Begrenzungszeichen ändern (aber keine eckigen Klammern verwenden).

Eingang:

why|[may express] surprise, reluctance, impatience, annoyance, indignation
whom|[used in] questions, subordination
whom|[possessive] whose
whom|[subjective] who
whoever|[objective] whomever
whoever|[possessive] whosever
who|[possessive] whose
who|[objective] whom

Gewünschte Ausgabe:

why|[may express] surprise, reluctance, impatience, annoyance, indignation
whom|[used in] questions, subordination%[possessive] whose%[subjective] who
whoever|[objective] whomever%[possessive] whosever
who|[possessive] whose%[objective] whom
MichaelCodes
quelle
Ist ein Zeilenumbruch am Anfang der Ausgabe erlaubt?
MIllIbyte
Kommentare zur ursprünglichen Frage hinzugefügt. Und, @mIllIbyte, ein Zeilenumbruch ist für mich irrelevant. Aber in meiner Idee gibt es keine Leerzeilen und keine Fehlerprüfung. Ich gehe davon aus, dass alle Zeilen Text enthalten und mindestens die erste Spalte und das Trennzeichen.
MichaelCodes
Nach den Testfällen zu urteilen, ist es sicher anzunehmen, dass alle Schlüssel gruppiert sind? Dh: ["A|some text", "B|other text", "A|yet some other text"]ist keine zu testende Eingabe, da die Schlüsselwörter für Anicht nacheinander in der Liste stehen.
Kevin Cruijssen
Ich nahm an, dass alle Schlüssel gruppiert sind. Es geht mir nicht um den Fall, in dem sie nicht behandelt werden, obwohl sie theoretisch nicht wie eindeutige Schlüssel behandelt würden.
MichaelCodes

Antworten:

7

Retina , 17 Bytes

  • Dank @MartinEnder werden 12 Byte gespeichert
  • 1 Byte gespeichert dank @ jimmy23013

Bewertung in ISO 8859-1-codierten Bytes.

Wird ;anstelle von |als Trennzeichen für Eingabefelder verwendet.

(?<=(.+;).+)¶\1
%

Probieren Sie es online aus.

Digitales Trauma
quelle
2
@LeakyNun Weil Lookarounds atomar sind. Bei der ersten Verwendung des Lookarounds wird das gesamte Präfix der Zeile erfasst, und danach wird die Regex-Engine nicht mehr zurückverfolgt.
Martin Ender
5

V , 16 13 Bytes

òí^¨á«©.*úsî±

Probieren Sie es online!

Du sagtest

Fühlen Sie sich frei, das Trennzeichen zu ändern

Also habe ich |als Trennzeichen gewählt. Wenn dies ungültig ist, lass es mich wissen und ich werde es ändern.

Erläuterung:

ò                #Recursively:
 í               #Search for the following on any line:
  ^¨á«©          #1 or more alphabetic characters at the beginning of the line
       .*        #Followed by anything
         ús      #Mark everything after this to be removed:
           î±    #A new line, then the first match again (one or more alphabetic characters)
DJMcMayhem
quelle
1
Dich wissen lassen???
Erik der Outgolfer
@ ΈρικΚωνσταντόπουλος Ja? Ist das ein Problem?
DJMcMayhem
Für dieses Puzzle können Sie das Trennzeichen ändern, z. B. "%" als Trennzeichen verwenden. nicht dh
Erik der Outgolfer
2
Das "|" Trennzeichen ist in Ordnung.
MichaelCodes
@MichaelCodes Können Sie weitere Testfälle hinzufügen, damit wir überprüfen können, ob eine Lösung zählt oder nicht?
DJMcMayhem
3

Perl -0n, 2 + 43 = 45 Bytes

s/
.*\|/%/g,print for/(.*\|)((?:
\1|.)*
)/g

Demo:

$ perl -0ne 's/
> .*\|/%/g,print for/(.*\|)((?:
> \1|.)*
> )/g' <<EOF
> why|[may express] surprise, reluctance, impatience, annoyance, indignation
> whom|[used in] questions, subordination
> whom|[possessive] whose
> whom|[subjective] who
> whoever|[objective] whomever
> whoever|[possessive] whosever
> who|[possessive] whose
> who|[objective] whom
> EOF
why|[may express] surprise, reluctance, impatience, annoyance, indignation
whom|[used in] questions, subordination%[possessive] whose%[subjective] who
whoever|[objective] whomever%[possessive] whosever
who|[possessive] whose%[objective] whom
Anders Kaseorg
quelle
3

SQL (PostgreSQL), 43 72 Bytes

COPY T FROM'T'(DELIMITER'|');SELECT a,string_agg(b,'%')FROM T GROUP BY A

Dies nutzt die praktische Funktion string_agg aggregate in PostgreSQL. Die Eingabe erfolgt aus einer Tabelle Tmit 2 Spalten Aund B. Um die Frage besser zu beantworten, habe ich den Befehl zum Laden von Daten aus einer Datei in die Tabelle eingefügt. Die Datei ist Tauch. Ich habe die Anweisung "table create" nicht gezählt.
Die Ausgabe wird ungeordnet sein, aber wenn das ein Problem ist, kann es mit einem behoben werdenORDER BY A

SQLFiddle wollte nicht für mich spielen, aber das ist es, was ich in meinem Setup bekomme.

CREATE TABLE T (A VARCHAR(9),B VARCHAR(30));

COPY T FROM'T'(DELIMITER'|');SELECT a,string_agg(b,'%')FROM T GROUP BY A
a   string_agg
--- ----------------------------------------
c   rest of fourth line
b   rest of second line%rest of third line
a   rest of first line
d   rest of fifth line%rest of sixth line
MickyT
quelle
1
Um fair zu sein, würde ich vorschlagen, einen COPY-Befehl einzufügen, um den Inhalt des in der Tabelle angegebenen Dateiformats zu lesen, da Sie sonst nicht dasselbe Problem wie alle anderen lösen.
Jules
@Jules Gut, ich dachte an diese Standard-I / O-Übereinstimmung, als ich antwortete. Wenn ich die Frage noch einmal lese, bearbeite ich die Antwort.
MickyT
2

C 127 Bytes

o[99],n[99],p=n;main(i){for(;gets(n);strncmp(o,n,i-p)?printf(*o?"\n%s":"%s",n),strcpy(o,n):printf(" /%s",i))i=1+strchr(n,'|');}

Funktioniert mit gcc. Das Trennzeichen wurde in geändert /. Übernimmt die Eingabe von stdin und schreibt die Ausgabe in stdout. Rufen Sie daher mit der Eingabeumleitung auf./a.out <filename

Ungolfed:

o[99],n[99] //declare int, to save two bytes for the bounds
,p=n; //p is an int, saves one byte as opposed to applying an (int) cast to n,
//or to declaring o and n as char arrays
main(i){for(;gets(n);strncmp(o,n,i-p //an (int)n cast would be needed;
// -(n-i) does not work either,
//because pointer arithmetics scales to (int*)
)?printf(*o?"\n%s":"%s" //to avoid a newline at the beginning of output
,n),strcpy(o,n):printf(" /%s",i))i=1+strchr(n,'|');}
mIllIbyte
quelle
1

Pyth - 15 Bytes

Wenn Sie ein paar Annahmen zum Problem machen, wird sich dies ändern, wenn OP klarstellt.

jm+Khhd-sdK.ghk

Probieren Sie es hier online aus .

Maltysen
quelle
Dies funktioniert nicht, wenn der "Schlüssel" eher ein Wort als ein einzelner Buchstabe ist. (OP in den Kommentaren geklärt)
DJMcMayhem
1

Python 3 - 146 Bytes

Die Eingabe ist der Dateiname oder der Dateipfad der Datei, die Ausgabe erfolgt nach stdout. Könnte viel kürzer sein, wenn ich Eingaben als Rohtext von der Kommandozeile nehmen könnte

Übernimmt die Eingabe von stdin und die Ausgabe von stdin. Setup mit Separator "|". Verwenden Sie das Trennzeichen, um die erste Beispieleingabe zu testen" | "

from itertools import*
for c,b in groupby([x.split("|")for x in input().split("\n")],key=lambda x:x[0]):print(c,"|"," % ".join((a[1]for a in b)))
Keatinge
quelle
Die Herausforderung erfordert nicht explizit, dass die Eingabe aus einer Datei gelesen wird. Ich schätze , hier gelten unsere Standard-E / A-Methoden . Und da andere Antworten auch die Eingabe von STDIN nehmen, denke ich, dass das OP damit einverstanden ist.
Denker
@DenkerAffe Okay, ich werde es editieren, es wird einfach völlig nutzlos sein, weil ich nicht glaube, dass Sie sogar tatsächliche mehrzeilige Eingaben von stdin geben können.
Keatinge
Sie können die Eingabe jedoch umleiten, wenn Sie das Skript ausführen.
MIllIbyte
1

Java 7, 167 Bytes

Es kann wahrscheinlich mehr Golf gespielt werden, wenn ein anderer Ansatz gewählt wird.

import java.util.*;Map c(String[]a){Map m=new HashMap();for(String s:a){String[]x=s.split("=");Object l;m.put(x[0],(l=m.get(x[0]))!=null?l+"%"+x[1]:x[1]);}return m;}

HINWEIS: Die obige Methode erstellt und gibt ein HashMapmit den gewünschten Schlüssel-Wert-Paaren zurück. Es wird jedoch nicht in der exakten Ausgabe wie in der Frage von OP mit einem |Trennzeichen zwischen den Schlüsseln und neuen Werten gedruckt . Nach MickeyTs SQL-Antwort zu urteilen , in der er eine Datenbanktabelle zurückgegeben hat, dachte ich, dass dies zulässig ist. Wenn nicht, sollten weitere Bytes für eine Druckfunktion hinzugefügt werden.

Ungolfed & Testcode:

import java.util.*;

class Main{

    static Map c(String[] a){
        Map m = new HashMap();
        for(String s : a){
            String[] x = s.split("\\|");
            Object l;
            m.put(x[0], (l = m.get(x[0])) != null
                            ? l + "%" + x[1]
                            : x[1]);
        }
        return m;
    }

    public static void main(String[] a){
        Map m = c(new String[]{
            "why|[may express] surprise, reluctance, impatience, annoyance, indignation",
            "whom|[used in] questions, subordination",
            "whom|[possessive] whose",
            "whom|[subjective] who",
            "whoever|[objective] whomever",
            "whoever|[possessive] whosever",
            "who|[possessive] whose",
            "who|[objective] whom"
        });

        // Object instead of Map.EntrySet because the method returns a generic Map
        for (Object e : m.entrySet()){
            System.out.println(e.toString().replace("=", "|"));
        }
    }
}

Ausgabe:

whoever|[objective] whomever%[possessive] whosever
whom|[used in] questions, subordination%[possessive] whose%[subjective] who
why|[may express] surprise, reluctance, impatience, annoyance, indignation
who|[possessive] whose%[objective] whom
Kevin Cruijssen
quelle
1

PowerShell, 85 Byte

Zeichenfolgen werden mithilfe der Hashtabelle zusammengeführt:

%{$h=@{}}{$k,$v=$_-split'\|';$h.$k=($h.$k,$v|?{$_})-join'%'}{$h.Keys|%{$_+'|'+$h.$_}}

Beispiel

Da PowerShell die stdin-Umleitung über nicht unterstützt <, gehe ich davon aus, dass Get-Content .\Filename.txt |diese als Standard-E / A-Methode verwendet wird.

Get-Content .\Filename.txt | %{$h=@{}}{$k,$v=$_-split'\|';$h.$k=($h.$k,$v|?{$_})-join'%'}{$h.Keys|%{$_+'|'+$h.$_}}

Ausgabe

whoever|[objective] whomever%[possessive] whosever
why|[may express] surprise, reluctance, impatience, annoyance, indignation
whom|[used in] questions, subordination%[possessive] whose%[subjective] who
who|[possessive] whose%[objective] whom
Beatcracker
quelle
1

APL, 42 Zeichen

{⊃{∊⍺,{⍺'%'⍵}/⍵}⌸/↓[1]↑{(1,¯1↓'|'=⍵)⊂⍵}¨⍵}
lstefano
quelle
ist kein Byte in der APL-Codierung.
Zacharý
0

Sed, 55 Bytes

:a N;:b s/^\([^|]*\)|\([^\n]*\)\n\1|/\1|\2 %/;ta;P;D;tb

Testlauf :

$ echo """why|[may express] surprise, reluctance, impatience, annoyance, indignation
> whom|[used in] questions, subordination
> whom|[possessive] whose
> whom|[subjective] who
> whoever|[objective] whomever
> whoever|[possessive] whosever
> who|[possessive] whose
> who|[objective] whom""" | sed ':a N;:b s/^\([^|]*\)|\([^\n]*\)\n\1|/\1|\2 %/;ta;P;D;tb'
why|[may express] surprise, reluctance, impatience, annoyance, indignation
whom|[used in] questions, subordination %[possessive] whose %[subjective] who
whoever|[objective] whomever %[possessive] whosever
who|[possessive] whose %[objective] whom
Aaron
quelle
0

q / kdb + 46 Bytes

Lösung:

exec"%"sv v by k from flip`k`v!("s*";"|")0:`:f

Beispiel:

q)exec"%"sv v by k from flip`k`v!("s*";"|")0:`:f
who    | "[possessive] whose%[objective] whom"
whoever| "[objective] whomever%[possessive] whosever"
whom   | "[used in] questions, subordination%[possessive] whose%[subjective] who"
why    | "[may express] surprise, reluctance, impatience, annoyance, indignation"

Erläuterung:

`:f            // assumes the file is named 'f'
("s*";"|")0:   // read in file, assume it has two columns delimitered by pipe
flip `k`v      // convert into table with columns k (key) and v (value)
exec .. by k   // group on key
"%"sv v        // join values with "%"
Streetster
quelle