Abréger un tableau

26

Objectif:

Étant donné un tableau de chaînes, créez des versions abrégées de chaque chaîne.

Spécification:

Pour ce défi, une abréviation correspond aux N premiers caractères d'une chaîne. Pour la chaîne abc: a, abet abcsont toutes les abréviations valides, alors que bc, et acne sont pas.

Étant donné un tableau de chaînes, nous voulons trouver l'ensemble d'abréviations le plus court, de sorte que, compte tenu de l'entrée et de toute abréviation, vous puissiez déterminer à quel élément de l'entrée à laquelle l'abréviation faisait référence.

Exemple:

Contribution: ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"]

Nous travaillons notre chemin à travers les cordes en commençant par la première.

  • Lundi est uniquement la chaîne d'élément avec un M, donc l'abréviation la plus courte possible est M.

  • Mardi commence par T, mais jeudi aussi. Cela signifie que nous essayons la chaîne TU. Comme aucune autre chaîne ne commence par cela, nous l'utilisons TU.

  • Mercredi est W, jeudi est Thet vendredi est F.

Plus d'exemples:

Input: "one,two,three,four,five,six,seven"
Output: "o,tw,th,fo,fi,si,se"

Input: "red,orange,yellow,green,blue,purple"
Output: "r,o,y,g,b,p"

Input: "a,ab,abc"
Output: Not valid! No abbreviation for `a` that doesn't apply to the other items.

Remarques:

  • Vous effectuez des entrées et des sorties d'une manière raisonnable.

  • Vous pouvez supposer que l'entrée sera toujours un tableau valide de chaînes.

  • Vous pouvez supposer qu'il y aura toujours une solution, contrairement au dernier cas de test.

  • Les chaînes seront uniquement constituées de caractères ASCII imprimables (ou des caractères imprimables de votre codage)

  • C'est du golf de code, donc moins d'octets gagnent!

Julian Lachniet
la source
Connexes: 1 , 2 , 3
Sp3000
5
Reproduction
Okx
2
Je ne pense pas que ce soit un double de ceux-ci (bien qu'ils soient tous assez similaires). En fait, je pense que c'est probablement le meilleur défi parmi les quatre; les autres ont tous des variantes qui les compliquent inutilement.
2
Le cas est-il important? En particulier, votre exemple de jour de semaine utilise une majuscule Upour mardi, mais une minuscule hpour jeudi.
Brian J
1
@Mego Ne modifiez pas mon article à moins qu'un modérateur ne le marque comme n'étant pas un doublon
Julian Lachniet

Réponses:

10

Rétine , 29 octets

!ms`^(.+?)(?!.+^\1)(?<!^\1.+)

L'entrée et la sortie sont des listes de chaînes séparées par des sauts de ligne.

Essayez-le en ligne! (Suite de tests avec séparation par des virgules pour plus de commodité.)

Explication

Cela correspond simplement à tous les préfixes avec une seule expression régulière et les affiche ( !). met ssont les modificateurs d'expression régulière habituels pour faire des ^débuts de ligne de .correspondance et des sauts de ligne de correspondance.

^(.+?)      # Match the shortest possible prefix of a line and capture
            # it in group 1.
(?!.+^\1)   # Make sure that this prefix does not show up in a line after
            # the current one.
(?<!^\1.+)  # Make sure that this prefix does not show up in a line before
            # the current one.
Martin Ender
la source
10

Python 2 , 87 86 octets

lambda a:[b[:min(i for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2)]for b in a]

Essayez-le en ligne!

ovs
la source
lambda a:[[b[:i]for i in range(len(b))if sum(s[:i]==b[:i]for s in a)<2][0]for b in a]pour 85 octets
Curtis Bechtel
le remplacement len(b)par 4**8enregistre 2 octets supplémentaires, en supposant que les chaînes ne dépasseront pas 65 536 caractères
Curtis Bechtel
8

JavaScript (ES6), 81 78 74 70 octets

Prend l'entrée comme un tableau de chaînes.

a=>a.map(s=>[...s].reduce((y,c)=>a.some(x=>x!=s&!x.indexOf(y))?y+c:y))

Formaté et commenté

a =>                          // given an array of strings 'a'
  a.map(s =>                  // for each string 's' in 'a':
    [...s].reduce((y, c) =>   //   starting with 'y' = first character of 's',
                              //   for each subsequent character 'c' of 's':
      a.some(x =>             //     if we find a string 'x' in 'a' such that:
        x != s &              //       - 'x' is different from 's'
        !x.indexOf(y)         //       - and 'y' appears at the beginning of 'x'
      ) ?                     //     then:
        y + c                 //       append 'c' to 'y'
      :                       //     else:
        y                     //       keep 'y' unchanged
    )                         //   end of reduce(): returns the correct prefix
  )                           // end of map()

Cas de test

Arnauld
la source
1
70 aussi, mais absolument autre: codegolf.stackexchange.com/a/113270/32091
Qwertiy
+1 pour reduce.
Neil
6

Gelée , 14 octets

;\w@þ=1Si1⁸ḣð€

Essayez-le en ligne!

Comment ça marche

;\w@þ=1Si1⁸ḣð€  Monadic link. Argument: A (string array)

            ð   Collect all links to the left into a chain (arity unknown) and
                begin a dyadic chain.
             €  Map the previous chain over A. The current chain is dyadic and the
                mapped one inherits its arity. Thus, the right will be A for all
                invocations, while the left argument will iterate over A.
                For each string s in A, the following happens.
;\                Cumulative reduce by concatenation; yield all prefixes of s.
  w@þ             Window index swapped table; for each string t in A and each
                  prefix p of s, find the index of the substring t in p.
                  The first index is 1; 0 means not found.
     =1           Compare the indices with 1, returning 1 iff t begins with p.
       S          Sum the Booleans across columns, counting the number of strings
                  in A that begin with a given prefix.
        i1        Find the first index of 1, the shortest prefix that is unique
                  across all strings in A.
          ⁸       Head; truncate s to the computed length.
Dennis
la source
6

Haskell , 48 octets

[_]#x=""
a#(c:y)=c:[z|d:z<-a,c==d]#y
f=map=<<(#)

Essayez-le en ligne!

  • fest la fonction principale, prenant une liste de Strings et renvoyant a String. Sa définition est un raccourci monadique pour f a=map (a#) a.
  • a#xexamine la chaîne xet la liste aet essaie de trouver le préfixe le plus court xqui est unique dans a. Si aa un seul élément, utilisez simplement la chaîne vide. S'il an'y a pas déjà un seul élément, coupez le premier caractère de x, filtrez et coupez les éléments de adépart avec le même caractère, puis récursivement.
Ørjan Johansen
la source
4

Mathematica, 64 octets

#&@@@StringCases[#,Shortest@x__/;Tr@Boole@StringStartsQ[#,x]<2]&
Martin Ender
la source
3

Gelée , 14 12 octets

ḣ€JṙLḶ$ḟ/€Ḣ€

Essayez-le en ligne!

Comment ça marche

ḣ€JṙLḶ$ḟ/€Ḣ€  Main link. Argument: A (string array)

  J           Yield the 1-based indices of A, i.e., [1, ..., len(A)].
ḣ€            Head each; for each string s in A, take the first 1, ..., and len(A) 
              characters. This builds the 2D array of prefixes of all strings in A.
    LḶ$       Length-unlength; yield [0, ..., len(A)-1].
   ṙ          Rotate the 2D array 0, ..., and len(A)-1 units to the left.
       ḟ/€    Reduce filterfalse each; for each rotation, remove all prefixes from
              the first set that also occur in later sets.
          Ḣ€  Head each; for each rotation, keep only the shortest unique prefix.
Dennis
la source
Je me demande simplement pourquoi vous avez 2 réponses ici? Je les aime tous les deux, mais je me demande simplement pourquoi vous avez deux réponses Jelly ici. :)
HyperNeutrino
Si j'ai deux approches concurrentielles similaires mais des approches suffisamment différentes, je les poste généralement dans des réponses distinctes.
Dennis
Bon point. Ouais, je me demandais juste. :) C'est une bonne idée; Je n'ai généralement pas plus d'une approche: P
HyperNeutrino
2

C ++ 11 (MinGW), 198 octets

#import<list>
#import<iostream>
f(std::list<std::string>l){int i,m;for(auto s:l){for(i=0,m=1;++i<s.length();)for(auto t:l)if(t!=s&&t.substr(0,i)==s.substr(0,i))m=i+1;std::cout<<s.substr(0,m)<<" ";}}

Appeler avec:

int main()
{
    f({"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"});
}

L'ajout d'un voididentifiant avant la fonction devrait également la faire compiler sur d'autres compilateurs, ajoutant ainsi 5 octets à la longueur.

Steadybox
la source
Ça devrait l'être void f..., ça ne marche pas autrement ... + 5 octets, malheureusement. Pour autant que je sache, les fonctions ont besoin de spécificateurs de type en C ++
M. Xcoder
D'ailleurs pour ça, approche exceptionnelle! Le golf en C / C ++ peut être douloureux
M. Xcoder
@ Mr.Xcoder Il compile cependant sur le compilateur MinGW que j'utilise. Il s'agit donc soit d'une extension du compilateur, soit d'un comportement non défini.
Steadybox
Je pense qu'il s'agit de l'extension du compilateur, sur GCC cela ne fonctionne pas ...
M. Xcoder
1
Tant qu'il y a un environnement dans lequel le code fonctionne, il est valide
undergroundmonorail
2

Javascript ES6, 70 caractères

s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

f=s=>(s+'#'+s).replace(/(\w+?)(\w*)(?=(\W(?!\1(?!\2))\w+)+$)|#.+/g,"$1")

console.log(f("one,two,three,four,five,six,seven")==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple")==="r,o,y,g,b,p")
console.log(f("one,two,three,four,five,six,seven".split`,`)==="o,tw,th,fo,fi,si,se")
console.log(f("red,orange,yellow,green,blue,purple".split`,`)==="r,o,y,g,b,p")

Qwertiy
la source
2

PHP, 131 120 119 118 octets

Merci @ Jörg pour preg_grep.

for(;a&$s=$argv[++$k];$i=+$t=!print"$t
")for(;a&$s[$i]&&1<count(preg_grep("(^".preg_quote($t.=$s[$i++]).")",$argv)););

prend l'entrée des arguments de la ligne de commande; imprime les résultats une ligne chacun.
Courez avec -nrou essayez-le en ligne .

  • peut échouer si l'entrée contient quelque chose commençant par -.
    +15 octets à corriger: remplacez le second $argvpar array_slice($argv,1).
  • renvoie des avertissements en PHP 7.1; remplacer a&par ""<(+1 octet) pour corriger.
  • -12 octets si l'entrée ne contient pas de caractères spéciaux d'expression régulière:
    insérez &($t.=$c)avant &&et remplacez ". preg_quote($t.=$c)."par $t.

panne

for(;a&$s=$argv[++$k];      # loop $s through arguments
    $i=+$t=!                # 3. reset $i and $t to empty
    print"$t\n")            # 2. print abbreviation
    for(;a&($c=$s[$i++])    # 1. loop $c through characters
        &&1<count(              # 3. if count==1, break loop
            preg_grep("(^"      # 2. find matching arguments
                . preg_quote(
                $t.=$c          # 1. append $c to abbreviation
            ).")",$argv)
        );
    );

version non regex, 131 130 octets

for($a=$argv;a&$s=$a[++$k];$i=+$t=!print"$t
")for($n=1;$n&&a&$c=$s[$i++];)for($n=$m=1,$t.=$c;a&$u=$a[$m++];)$n-=0===strpos($u,$t);

Remplacez le premier et le dernier a&par ""<(+2 octets) pour corriger pour PHP 7.1.

panne

for($a=$argv;a&$s=$a[++$k];     # loop through arguments
    $i=+$t=!print"$t\n")            # 2. print abbreviation, reset $i and $t to empty
    for($n=1;$n&&a&$c=$s[$i++];)    # 1. loop through characters while $n<>0
        for($n=$m=1,                    # reset $n and $m to 1
            $t.=$c;                     # append current character to prefix
            a&$u=$a[$m++];              # loop through arguments:
        )$n-=0===strpos($u,$t);         # -$n = number of matching strings -1

note complètement inintéressante:
strstr($u,$t)==$uet 0===strpos($u,$t)ont la même longueur et le même résultat.

Titus
la source
Utilisez un vrai caractère de nouvelle ligne ( 0x0A) au lieu de \n, cela économisera un octet;).
Blackhole
@Blackhole Thanks; J'ai oublié ça cette fois.
Titus
1

PHP, 127 octets

ne fonctionne pas avec des tableaux invalides

<?foreach($a=$_GET as$k=>$v)for($i=0,$c=2,$s="";$c>1;$r[$k]=$s)$c=count(preg_grep("_^".($s.=$v[$i++])._,$a));echo join(",",$r);

PHP, 132 octets

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".($s.=$v[$i++])._,$a))==1){$r[]=$s;break;}echo join(",",$r);

Version en ligne

151 octets prennent en charge les caractères spéciaux

<?foreach($a=$_GET as$v)for($i=0,$s="";a&$v[$i];)if(count(preg_grep("_^".preg_quote($s=substr($v,0,++$i),_)._,$a))==1){$r[]=$s;break;}echo join(",",$r);

PHP, 140 octets

<?foreach($a=$_GET as$k=>$v)for($i=0;a&$v[$i];)if(count(preg_grep("#^".($s=substr($v,0,++$i))."#",$a))==1){$r[]=$s;break;}echo join(",",$r);
Jörg Hülsermann
la source
Cela échouera si l'entrée contient des caractères spéciaux regex. J'aurais 113 octets au lieu de 131 sinon.
Titus
@Titus Dans ce cas, je pourrais ajouter un preg_quoteMake only 10 Bytes more
Jörg Hülsermann
Il échouera également si l'entrée contient 0. Mais vous pouvez enregistrer un octet avec $i=+$s="".
Titus
et vous pouvez supprimer le count()-count()truc: l'entrée est garantie d'être valide (-21 octets). Je pense que je pourrais réparer et jouer au golf jusqu'à 120 octets. $_GETétait une bonne idée!
Titus
@Titus Je n'ai pas réalisé que seuls les tableaux valides sont autorisés. Oui, cela échouerait si la chaîne contenait un zéro, mais cela était né d'une idée
Jörg Hülsermann
0

Clojure, 118 octets

#(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s))))

Cela fonctionne sur les préfixes jusqu'à la longueur de 1e2mais le même nombre d'octets peut prendre en charge jusqu'à 1e9. iboucles longueurs de préfixes, Sest la séquence de sous-chaînes de longueur i. Le dernier forremplace les sous-chaînes avec nillesquelles se produisent plus d'une fois. La réduction conserve la première valeur non nulle pour chaque chaîne, dommage qu'elle orne soit pas une fonction, j'ai donc dû la boucler.

Cela renvoie en fait des listes de listes de personnages comme ((\M) (\T \u) (\W) (\T \h) (\F)), mais je suppose que c'est acceptable. Clojure est assez verbeux avec des cordes, et subslancerait StringIndexOutOfBoundsExceptioncontrairement take.

Exemples complets:

(def f #(reduce(partial map(fn[a b](or a b)))(for[i(range 1e2)S[(for[c %](take i c))]](for[s S](if(=((frequencies S)s)1)s)))))

(f ["Monday", "Tuesday", "Wednesday", "Thursday", "Friday"])
(f (re-seq #"[^,]+" "one,two,three,four,five,six,seven"))
(f (re-seq #"[^,]+" "red,orange,yellow,green,blue,purple"))
NikoNyrh
la source
0

SQL (version PostgreSQL 9.4), 219 octets

Maintenant, pour la réponse la plus longue :) Je ne pense pas que cela puisse même battre Java. Je vais essayer d'en raser un peu plus. En espérant me débarrasser de l'une des requêtes imbriquées, mais je n'aime pas mes chances.
Cela suppose qu'il existe une table contenant les chaînes sur lesquelles travailler. Comme il s'agit de SQL, l'ordre de retour n'est pas garanti identique à l'ordre de la table et, dans ce cas, peu probable. Si c'est un problème, je supprimerai.

SELECT R FROM(SELECT*,RANK()OVER(PARTITION BY A ORDER BY C,N)Z FROM(SELECT*,SUM(1)OVER(PARTITION BY R)C FROM(SELECT*FROM A JOIN LATERAL(select left(A,n)R,N FROM generate_series(1,length(A))S(n))L ON 1=1)X)Y)Z WHERE Z=1


Explication de SQL Fiddle

  SELECT *
  FROM A 
    JOIN LATERAL(SELECT LEFT(A,n)R,N 
    FROM generate_series(1,length(A))S(n))L ON 1=1

La requête la plus interne utilise generate_serieset une LATERALjointure pour créer des lignes pour la chaîne divisée en longueurs croissantes, donc «un» devient «o», «on», «un». Le nombre de caractères dans le retour est également conservé.

SELECT 
  *,
  SUM(1)OVER(PARTITION BY R)C
FROM ( ... )X

Ensuite, nous ajoutons le nombre d'enregistrements qui ont le même résultat. Par exemple, «f» de quatre et cinq en a 2, mais «fo» et «fi» en ont chacun un. L' OVERinstruction en SQL peut être assez puissante. COUNT(*)serait la manière habituelle, mais SUM(1)donne le même résultat.

SELECT 
  *,
  RANK()OVER(PARTITION BY A ORDER BY C,N)Z
FROM ( ... )Y

Ensuite, nous classons les résultats pour chaque entrée en fonction du moins de répétitions et de caractères. ROW_NUMBERfonctionnerait ici aussi, mais est plus long.

SELECT R FROM ( ... )Z WHERE Z=1;

Enfin, nous sélectionnons le numéro de rang le plus bas pour chaque mot.

MickyT
la source
0

Pure Bash , 146 octets

for i in $@;{ K=1;U=${i::1};((M++));L=;while [[ `for v in $@;{ ((L++));(($L!=$M))&&echo ${v::K}||:;}` =~ $U ]];do U=${i::K};((K++));done;echo $U;}

Essayez-le en ligne!

R. Kap
la source
0

APL (Dyalog) , 27 octets

{⍵↑¨⍨1⍳⍨¨↓+/(↑,⍵)∘.(⊃⍷)⍵}

Essayez-le en ligne!

{ une fonction anonyme, où ⍵ représente l'argument ...

∘.( une table de fonction où la fonction est

   le premier élément de

   la liste booléenne "l'argument gauche commence ici dans l'argument droit?"

) où sont les bons arguments

 les arguments

( et l'argument de gauche est

   une table avec des rangées

  ,/ préfixes de

  ¨ chacun des

   les arguments

+/ somme à travers (compte le nombre d'arguments commençant par ce préfixe)

 diviser le tableau en liste de lignes

⍳⍨¨ dans chacun, trouver l'emplacement du premier

1 un (c'est-à-dire le premier préfixe qui ne dirige qu'un seul argument)

↑¨⍨ pour chaque emplacement, prend autant de caractères de l'élément correspondant de

 l'argument

} fin de la fonction anonyme

Adam
la source
0

PowerShell, 151 139 octets

$x,$w=@(),$args[0];$w|%{$k=$_;$a='';foreach($l in [char[]]$k){$a+=$l;if($a-notin$x-and!($w|?{$_-ne$k-and$_-like"$a*"})){$x+=$a;break;}}};$x

Intéressé s'il y a une meilleure façon de le faire. J'ai dû utiliser un foreach(sur un |%) pour pouvoir effectuer un breakdans la boucle imbriquée sans l'étiqueter.

Edit: 2 golfs d'AdmBorkBork

Tor
la source
1
Je n'ai pas parcouru le code directement, mais vous pourriez sûrement utiliser à la -notinplace de -not$x.contains($a)et !($w...au lieu de -not($w...sauvegarder quelques octets, oui?
AdmBorkBork
0

APL, 26 octets

{⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}

Explication:

  • ↓↑⍵: remplir chaque chaîne pour qu'elle corresponde à la longueur de la plus longue chaîne
  • ∘.(... )⍨: pour chaque paire de chaînes possible, recherchez le préfixe partagé:
    • : inégalité de tableau
    • : et
    • =: égalité par élément
    • ∧\: and-scan (conserver uniquement les correspondances principales)
  • +/¨: additionne chaque vecteur du tableau, donnant la longueur des préfixes partagés
  • ⌈/: trouver la valeur maximale dans chaque colonne
  • 1+: ajoutez-en un, en donnant le nombre de caractères nécessaires pour garder chaque chaîne unique
  • ⍵↑¨⍨: prendre autant de caractères de chaque chaîne

Tester:

      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'Monday' 'Tuesday' 'Wednesday' 'Thursday' 'Friday'
┌─┬──┬─┬──┬─┐
│M│Tu│W│Th│F│
└─┴──┴─┴──┴─┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'one' 'two' 'three' 'four' 'five' 'six' 'seven'
┌─┬──┬──┬──┬──┬──┬──┐
│o│tw│th│fo│fi│si│se│
└─┴──┴──┴──┴──┴──┴──┘
      {⍵↑¨⍨1+⌈/+/¨∘.(∧\=∧≢)⍨↓↑⍵}'red' 'orange' 'yellow' 'green' 'blue' 'purple'
┌─┬─┬─┬─┬─┬─┐
│r│o│y│g│b│p│
└─┴─┴─┴─┴─┴─┘
marinus
la source
0

Q, 93 octets

{n:1;{$[any e:(,/)1<{(+/)i like x}each i:z#'x;[z+:1;y:?[e;z#'x;i];.z.s[x;y;z]];y]}[x;n#'x;n]}

Résolu récursivement, prend la chaîne en entrée, obtient les n premiers éléments de chaque chaîne à chaque récursivité. Si l'un de ces éléments n'est pas unique, il les remplace par les premiers n + 1 éléments.

Daniel Plainview
la source