Oneliner pour fusionner les lignes avec le même premier champ

15

Ceci est ma première question sur le codegolf, donc je m'excuse à l'avance si ce n'est pas approprié, et je me réjouis de tout commentaire.

J'ai un fichier avec ce 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

Le contenu réel varie, tout comme le délimiteur. Le contenu n'est que du texte. Le délimiteur n'apparaît qu'une fois par ligne. Pour ce puzzle, n'hésitez pas à modifier le délimiteur, par exemple, utilisez "%" comme délimiteur.

Sortie désirée:

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

J'ai déjà des scripts ruby ​​et awk pour fusionner cela, mais je soupçonne qu'il est possible d'avoir un court oneliner. c'est-à-dire une doublure qui peut être utilisée avec des tuyaux et d'autres commandes sur la ligne de commande. Je ne peux pas le comprendre, et mon propre script est trop long pour simplement compresser sur la ligne de commande.

Les caractères les plus courts sont préférés. L'entrée n'est pas nécessairement triée, mais nous souhaitons uniquement fusionner les lignes consécutives avec les premiers champs correspondants. Il y a un nombre illimité de lignes avec les premiers champs correspondants. Le champ 1 peut être n'importe quoi, par exemple des noms de fruits, des noms propres, etc.

(Je fonctionne sur MacOS, donc je suis personnellement le plus intéressé par les implémentations qui fonctionnent sur Mac).


Voici un deuxième exemple / test. Remarquez "|" est le délimiteur. L'espace avant le "|" est hors de propos, et si le renvoi doit être considéré comme faisant partie de la clé. J'utilise "%" comme délimité dans la sortie, mais encore une fois, n'hésitez pas à changer le délimiteur (mais n'utilisez pas de crochets).

Contribution:

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

Sortie désirée:

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
la source
Une nouvelle ligne au début de la sortie est-elle autorisée?
mIllIbyte
ajout de commentaires dans la question d'origine. Et, @mIllIbyte, une nouvelle ligne ne me concerne pas. Mais dans mon idée, il n'y a pas de lignes vides et pas de vérification d'erreur. Je suppose que toutes les lignes ont du texte, et au moins la première colonne et le délimiteur.
MichaelCodes
À en juger par les cas de test, est-il prudent de supposer que toutes les clés sont regroupées? C'est-à-dire: ["A|some text", "B|other text", "A|yet some other text"]n'est pas une entrée souhaitée à tester, car les mots clés pour Ane sont pas l'un après l'autre dans la liste.
Kevin Cruijssen
J'ai supposé que toutes les clés étaient regroupées. Je ne suis pas concerné par le cas où ils ne le sont pas, bien qu'en théorie, ce ne serait pas qu'ils seraient traités comme des clés uniques.
MichaelCodes

Réponses:

7

Rétine , 17 octets

  • 12 octets enregistrés grâce à @MartinEnder
  • 1 octet enregistré grâce à @ jimmy23013

Noté en octets codés ISO 8859-1.

Utilise ;au lieu de |comme séparateur de champ d'entrée.

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

Essayez-le en ligne.

Traumatisme numérique
la source
2
@LeakyNun Parce que les contournements sont atomiques. La première fois que le lookaround est utilisé, il capture l'intégralité du préfixe de la ligne, et ensuite le moteur regex n'y reviendra plus.
Martin Ender
5

V , 16 13 octets

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

Essayez-le en ligne!

Tu as dit

N'hésitez pas à changer le délimiteur

J'ai donc choisi |comme délimiteur. Si ce n'est pas valide, faites-le moi savoir et je le changerai.

Explication:

ò                #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
la source
1
Te faire savoir???
Erik the Outgolfer
@ ΈρικΚωνσταντόπουλος Oui? Est-ce un problème?
DJMcMayhem
Pour ce puzzle, n'hésitez pas à modifier le délimiteur, par exemple, utilisez "%" comme délimiteur. pas ie
Erik l'Outgolfer
2
Le "|" le délimiteur est très bien.
MichaelCodes
@MichaelCodes Pourriez-vous ajouter d'autres cas de test afin que nous puissions vérifier si une solution compte ou non?
DJMcMayhem
3

Perl -0n, 2 + 43 = 45 octets

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

Démo:

$ 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
la source
3

SQL (PostgreSQL), 43 72 octets

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

Cela tire parti de la fonction d'agrégation string_agg pratique dans PostgreSQL. L'entrée provient d'une table appelée Tavec 2 colonnes Aet B. Pour mieux répondre à la question, j'ai inclus de commander pour charger les données d'un fichier dans la table. Le fichier l'est Taussi. Je n'ai pas compté l'instruction create table.
La sortie ne sera pas ordonnée, mais si c'est un problème, elle peut être corrigée avec unORDER BY A

SQLFiddle ne voulait pas jouer pour moi, mais c'est ce que j'obtiens dans ma configuration.

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
la source
1
Pour être honnête, je suggère également d'inclure une commande COPY pour lire le contenu du format de fichier spécifié dans le tableau, sinon vous ne résolvez pas le même problème que tout le monde.
Jules
@ Jules Assez bien, je pensais à ce consensus d'E / S par défaut quand j'ai répondu. En relisant la question, je modifierai la réponse.
MickyT
2

C, 127 octets

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

Fonctionne avec gcc. Délimiteur remplacé par /. Prend l'entrée de stdin et écrit la sortie dans stdout, donc appelez avec la redirection d'entrée./a.out <filename

Non 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
la source
1

Pyth - 15 octets

Faire quelques hypothèses sur le problème changera lorsque OP clarifiera.

jm+Khhd-sdK.ghk

Essayez-le en ligne ici .

Maltysen
la source
Cela ne fonctionne pas si la "clé" est un mot plutôt qu'une seule lettre. (OP clarifié dans les commentaires)
DJMcMayhem
1

Python 3 - 146 octets

L'entrée est le nom de fichier ou le chemin d'accès au fichier, la sortie est vers stdout. Pourrait être beaucoup plus court si je pouvais prendre l'entrée comme texte brut à partir de la ligne de commande

Prend les entrées de stdin et les sorties vers stdin. Configuration avec séparateur "|". Pour tester le premier exemple d'entrée, utilisez le séparateur" | "

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
la source
Le défi n'exige pas explicitement que l'entrée soit lue à partir d'un fichier, donc je suppose que nos méthodes d'E / S par défaut s'appliquent ici. Et puisque d'autres réponses prennent également l'entrée de STDIN, je suppose que l'OP est bien avec elle.
Denker
@DenkerAffe Très bien, je vais le modifier, il sera tout simplement inutile car je ne pense pas que vous puissiez même donner une entrée multiligne réelle depuis stdin.
Keatinge
Mais vous pouvez effectuer une redirection d'entrée lorsque vous exécutez le script.
mIllIbyte
1

Java 7, 167 octets

Il peut probablement être joué plus en utilisant une approche différente.

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

REMARQUE: la méthode ci-dessus crée et renvoie un HashMapavec les paires clé-valeur souhaitées. Cependant, il ne l'imprime pas dans la sortie exacte comme dans la question OP avec |comme délimiteur de sortie entre les clés et les nouvelles valeurs. À en juger par la réponse SQL de MickeyT où il a renvoyé une table de base de données, je me suis dit que c'était autorisé; sinon, plus d'octets doivent être ajoutés pour une fonction d'impression.

Code non testé et 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("=", "|"));
        }
    }
}

Production:

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
la source
1

PowerShell, 85 octets

Les chaînes sont fusionnées à l'aide de la table de hachage:

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

Exemple

Étant donné que PowerShell ne prend pas en charge la redirection stdin via <, je suppose que ce Get-Content .\Filename.txt |sera utilisé comme méthode d'E / S par défaut.

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

Production

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
la source
1

APL, 42 caractères

{⊃{∊⍺,{⍺'%'⍵}/⍵}⌸/↓[1]↑{(1,¯1↓'|'=⍵)⊂⍵}¨⍵}
lstefano
la source
n'est pas un octet dans l'encodage APL.
Zacharý
0

Sed, 55 octets

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

Essai :

$ 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
la source
0

q / kdb +, 46 octets

Solution:

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

Exemple:

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"

Explication:

`: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
la source