Oneliner para fusionar líneas con el mismo primer campo

15

Esta es mi primera pregunta de codegolf, así que me disculpo de antemano si no es apropiado, y agradezco cualquier comentario.

Tengo un archivo con este 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

Los contenidos reales varían, al igual que el delimitador. Los contenidos son solo texto. El delimitador solo aparece una vez por línea. Para este rompecabezas, siéntase libre de cambiar el delimitador, por ejemplo, use "%" como delimitador.

Salida deseada:

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

Ya tengo los scripts ruby ​​y awk para fusionar esto, pero sospecho que es posible tener una línea corta. es decir, una línea que se puede usar junto con tuberías y otros comandos en la línea de comandos. No puedo entenderlo, y mi propio script es demasiado largo para comprimir en la línea de comando.

Se prefieren los caracteres más cortos. La entrada no está necesariamente ordenada, pero solo nos interesa fusionar líneas consecutivas con los primeros campos coincidentes. Hay líneas ilimitadas con los primeros campos coincidentes. El campo 1 podría ser cualquier cosa, por ejemplo, nombres de frutas, nombres propios, etc.

(Ejecuto en MacOS, por lo que personalmente estoy más interesado en las implementaciones que se ejecutan en Mac).


Aquí hay un segundo ejemplo / prueba. Aviso "|" Es el delimitador. El espacio antes del "|" es irrelevante, y si se reenvía debe considerarse parte de la clave. Estoy usando "%" como delimitado en la salida, pero nuevamente, siéntase libre de cambiar el delimitador (pero no use corchetes).

Entrada:

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

Salida deseada:

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
fuente
¿Se permite una nueva línea al comienzo de la salida?
mIllIbyte 01 de
comentarios agregados en la pregunta original. Y, @mIllIbyte, una nueva línea es irrelevante para mí. Pero en mi idea, no hay líneas en blanco, ni verificación de errores. Supongo que todas las líneas tienen texto, y al menos la primera columna y el delimitador.
MichaelCodes
A juzgar por los casos de prueba, ¿es seguro asumir que todas las claves están agrupadas? Es decir: ["A|some text", "B|other text", "A|yet some other text"]no es una entrada deseada para probar, ya que las palabras clave para Ano son una tras otra en la lista.
Kevin Cruijssen
Supuse que todas las claves están agrupadas. No me preocupa el caso en que no lo son, aunque en teoría, no serían tratados como claves únicas.
MichaelCodes

Respuestas:

7

Retina , 17 bytes

  • 12 bytes guardados gracias a @MartinEnder
  • 1 byte guardado gracias a @ jimmy23013

Puntuación en bytes codificados ISO 8859-1.

Utiliza en ;lugar de |como el separador de campo de entrada.

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

Pruébalo en línea.

Trauma digital
fuente
2
@LeakyNun Porque las búsquedas son atómicas. La primera vez que se usa el lookaround captura el prefijo completo de la línea, y luego el motor de expresiones regulares no retrocederá más en él.
Martin Ender
5

V , 16 13 bytes

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

Pruébalo en línea!

Tu dijiste

Siéntase libre de cambiar el delimitador

Así que elegí |como delimitador. Si esto no es válido, avíseme y lo cambiaré.

Explicación:

ò                #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
fuente
1
¿¿¿Dejarte saber???
Erik the Outgolfer
@ ΈρικΚωνσταντόπουλος ¿Sí? ¿Es eso un problema?
DJMcMayhem
Para este rompecabezas, siéntase libre de cambiar el delimitador, por ejemplo , use "%" como delimitador. no es así
Erik the Outgolfer
2
El "|" El delimitador está bien.
MichaelCodes
@MichaelCodes ¿Podría agregar algunos casos de prueba más para que podamos verificar si una solución cuenta o no?
DJMcMayhem
3

Perl -0n, 2 + 43 = 45 bytes

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

Manifestación:

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

SQL (PostgreSQL), 43 72 bytes

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

Esto aprovecha la práctica función agregada string_agg en PostgreSQL. La entrada es de una tabla llamada Tcon 2 columnas Ay B. Para cumplir mejor con la pregunta, he incluido el comando para cargar datos de un archivo en la tabla. El archivo también lo es T. No he contado la declaración de creación de tabla.
La salida no estará ordenada, pero si eso es un problema, se puede solucionar con unORDER BY A

SQLFiddle no quería jugar para mí, pero esto es lo que obtengo en mi configuración.

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
fuente
1
Para ser justos, sugeriría incluir también un comando COPIAR para leer el contenido del formato de archivo especificado en la tabla, de lo contrario no resolverá el mismo problema que todos los demás.
Jules
@Jules Justo lo suficiente, estaba pensando en este consenso de E / S predeterminado cuando respondí. Volviendo a leer la pregunta, editaré la respuesta.
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,'|');}

Funciona con gcc. Se cambió el delimitador a /. Toma la entrada de stdin y escribe la salida en stdout, así que llama con la redirección de entrada./a.out <filename

Sin golf:

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
fuente
1

Pyth - 15 bytes

Hacer algunas suposiciones sobre el problema cambiará cuando OP aclare.

jm+Khhd-sdK.ghk

Pruébelo en línea aquí .

Maltysen
fuente
Esto no funciona si la "clave" es una palabra, en lugar de una sola letra. (OP aclarado en los comentarios)
DJMcMayhem
1

Python 3 - 146 bytes

La entrada es el nombre del archivo o la ruta del archivo, la salida es stdout. Podría ser mucho más corto si pudiera tomar la entrada como texto sin formato desde la línea de comando

Toma entrada de stdin y salidas a stdin. Configuración con separador "|". Para probar la entrada de primer ejemplo, use el separador" | "

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
fuente
El desafío no requiere explícitamente que la entrada se lea desde un archivo, por lo que creo que nuestros métodos de E / S predeterminados se aplican aquí. Y dado que otras respuestas también toman la entrada de STDIN, supongo que el OP está bien con eso.
Denker
@DenkerAffe Muy bien, lo editaré, será completamente inútil porque no creo que puedas dar una entrada multilínea real desde stdin.
Keatinge
Pero puede hacer una redirección de entrada cuando ejecuta el script.
mIllIbyte
1

Java 7, 167 bytes

Probablemente se pueda jugar más al golf utilizando un enfoque diferente.

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: El método anterior crea y devuelve a HashMapcon los pares clave-valor deseados. Sin embargo, no lo imprime en la salida exacta como en la pregunta de OP con |como delimitador de salida entre las claves y los nuevos valores. A juzgar por la respuesta SQL de MickeyT donde devolvió una tabla de base de datos, pensé que esto estaba permitido; si no se deben agregar más bytes para una función de impresión.

Ungolfed y código de prueba:

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

Salida:

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
fuente
1

PowerShell, 85 bytes

Las cadenas se fusionan usando la tabla hash:

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

Ejemplo

Dado que PowerShell no admite la redirección de stdin mediante <, supongo que Get-Content .\Filename.txt |se usará como método de E / S predeterminado.

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

Salida

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
fuente
1

APL, 42 caracteres

{⊃{∊⍺,{⍺'%'⍵}/⍵}⌸/↓[1]↑{(1,¯1↓'|'=⍵)⊂⍵}¨⍵}
lstefano
fuente
No es un byte en la codificación APL.
Zacharý
0

Sed, 55 bytes

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

Prueba de funcionamiento :

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

q / kdb +, 46 bytes

Solución:

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

Ejemplo:

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"

Explicación:

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