Oneliner per unire le linee con lo stesso primo campo


15

Questa è la mia prima domanda su codegolf, quindi mi scuso in anticipo se non è appropriato e accolgo con favore qualsiasi feedback.

Ho un file con questo formato:

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

I contenuti effettivi variano, così come il delimitatore. I contenuti sono solo testo. Il delimitatore appare solo una volta per riga. Per questo puzzle, sentiti libero di cambiare il delimitatore, ad esempio usa "%" come delimitatore.

Uscita desiderata:

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

Ho già entrambi gli script Ruby e Awk per unire questo, ma sospetto che sia possibile avere un breve line-up. vale a dire un one-liner che può essere utilizzato insieme a tubi e altri comandi sulla riga di comando. Non riesco a capirlo, e il mio script è troppo lungo da comprimere solo dalla riga di comando.

Personaggi più corti preferiti. L'input non è necessariamente ordinato, ma siamo interessati solo a unire le righe consecutive con i primi campi corrispondenti. Esistono linee illimitate con i primi campi corrispondenti. Il campo 1 potrebbe essere qualsiasi cosa, ad esempio nomi di frutti, nomi propri, ecc.

(Corro su MacOS, quindi sono personalmente più interessato alle implementazioni che girano su Mac).


Ecco un secondo esempio / test. Avviso "|" è il delimitatore. Lo spazio prima del "|" è irrilevante e se il rinvio deve essere considerato parte della chiave. Sto usando "%" come delimitato nell'output, ma di nuovo, mi sento libero di cambiare il delimitatore (ma non uso parentesi quadre).

Ingresso:

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

Uscita desiderata:

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

È consentita una nuova riga all'inizio dell'output?
mIllIbyte,

aggiunti commenti alla domanda originale. E, @mIllIbyte, una nuova riga è irrilevante per me. Ma nella mia idea, non ci sono righe vuote e nessun controllo degli errori. Presumo che tutte le righe abbiano testo e almeno la prima colonna e il delimitatore.
MichaelCodes

A giudicare dai casi di test, è salvo supporre che tutte le chiavi siano raggruppate? Vale a dire: ["A|some text", "B|other text", "A|yet some other text"]non è un input desiderato da testare, poiché le parole chiave per Anon sono una dopo l'altra nell'elenco.
Kevin Cruijssen,

Presumo che tutte le chiavi siano raggruppate. Non mi preoccupo del caso in cui non lo sono, anche se in teoria non verrebbero trattati come chiavi uniche.
MichaelCodes

Risposte:


7

Retina , 17 byte

  • 12 byte salvati grazie a @MartinEnder
  • 1 byte salvato grazie a @ jimmy23013

Segnati in byte codificati ISO 8859-1.

Utilizza ;invece |come separatore del campo di input.

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

Provalo online.



2
@LeakyNun Perché i lookaround sono atomici. La prima volta che viene utilizzato il lookaround, acquisisce l'intero prefisso della linea e, successivamente, il motore regex non tornerà più indietro.
Martin Ender,

5

V , 16 13 byte

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

Provalo online!

Tu hai detto

Sentiti libero di cambiare il delimitatore

Quindi ho scelto |come delimitatore. Se questo non è valido, fammi sapere e lo cambierò.

Spiegazione:

ò                #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)

1
Farti sapere???
Erik the Outgolfer,

@ ΈρικΚωνσταντόπουλος Sì? È un problema?
DJMcMayhem

Per questo puzzle, sentiti libero di cambiare il delimitatore, ad esempio usa "%" come delimitatore. non vale a dire
Erik the Outgolfer,

2
Il "|" il delimitatore va bene.
MichaelCodes

@MichaelCodes Potresti aggiungere altri casi di test in modo da poter verificare se una soluzione conta o no?
DJMcMayhem

3

Perl -0n, 2 + 43 = 45 byte

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

3

SQL (PostgreSQL), 43 72 byte

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

Questo sfrutta la pratica funzione aggregata string_agg in PostgreSQL. L'input proviene da una tabella chiamata Tcon 2 colonne Ae B. Per soddisfare meglio la domanda, ho incluso il comando di caricare i dati da un file nella tabella. Anche il file è T. Non ho conteggiato la dichiarazione di creazione della tabella.
L'output sarà non ordinato, ma se questo è un problema può essere risolto con unORDER BY A

SQLFiddle non voleva giocare per me, ma questo è ciò che ottengo nella mia configurazione.

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

1
Ad essere sinceri, suggerirei di includere un comando COPY per leggere anche il contenuto del formato file specificato nella tabella, altrimenti non risolverai lo stesso problema di tutti gli altri.
Jules,

@Jules Abbastanza giusto, stavo pensando a questo consenso i / o predefinito quando ho risposto. Rileggendo la domanda, modificherò la risposta.
MickyT

2

C, 127 byte

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

Funziona con gcc. Delimitatore modificato in /. Prende l'input da stdin e scrive l'output su stdout, quindi chiama con reindirizzamento dell'input./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,'|');}

1

Pyth - 15 byte

Fare alcune ipotesi sul problema cambierà quando chiarirà l'OP.

jm+Khhd-sdK.ghk

Provalo online qui .


Questo non funziona se la "chiave" è una parola, piuttosto che una singola lettera. (OP chiarito nei commenti)
DJMcMayhem

1

Python 3 - 146 byte

L'input è il nome file o il percorso del file, l'output è stdout. Potrebbe essere molto più breve se potessi prendere l'input come testo non elaborato dalla riga di comando

Prende input da stdin e output in stdin. Installazione con separatore "|". Per testare il primo esempio di input utilizzare il separatore" | "

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

La sfida non richiede esplicitamente che l'input sia letto da un file, quindi immagino che i nostri metodi I / O predefiniti si applichino qui. E poiché anche altre risposte prendono l'input da STDIN, suppongo che l'OP vada bene con esso.
Denker,

@DenkerAffe Va bene lo modificherò, sarà completamente inutile perché non penso che tu possa anche dare un vero input multilinea da stdin.
Keatinge,

Ma puoi eseguire il reindirizzamento dell'input quando esegui lo script.
mIllIbyte

1

Java 7, 167 byte

Probabilmente si può giocare a golf di più usando un approccio diverso.

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

NOTA: il metodo sopra crea e restituisce un HashMapcon le coppie chiave-valore desiderate. Tuttavia, non lo stampa nell'output esatto come nella domanda di OP con |come delimitatore di output tra le chiavi e i nuovi valori. A giudicare dalla risposta SQL di MickeyT dove ha restituito una tabella di database, ho pensato che fosse consentito; se non è necessario aggiungere più byte per una funzione di stampa.

Codice non testato e test:

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("=", "|"));
        }
    }
}

Produzione:

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

1

PowerShell, 85 byte

Le stringhe vengono unite usando la tabella hash:

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

Esempio

Poiché PowerShell non supporta il reindirizzamento stdin tramite <, suppongo che Get-Content .\Filename.txt |verrà utilizzato come metodo I / O predefinito.

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

Produzione

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

1

APL, 42 caratteri

{⊃{∊⍺,{⍺'%'⍵}/⍵}⌸/↓[1]↑{(1,¯1↓'|'=⍵)⊂⍵}¨⍵}

non è un byte nella codifica APL.
Zacharý,

0

Sed, 55 byte

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

Prova :

$ 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

0

q / kdb +, 46 byte

Soluzione:

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

Esempio:

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"

Spiegazione:

`: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 "%"
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.