Abreviar una matriz


26

Gol:

Dada una serie de cadenas, cree versiones abreviadas de cada cadena.

Especificación:

Para este desafío, una abreviatura son los primeros N caracteres de una cadena. Para la cadena abc: a, ab, y abcson todas las abreviaturas válidos, mientras que bc, y acno lo son.

Dada una serie de cadenas, queremos encontrar el conjunto más corto de abreviaturas, de modo que dada la entrada y cualquier abreviatura, pueda determinar a qué elemento de la entrada se refería la abreviatura.

Ejemplo:

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

Nos abrimos paso a través de las cadenas comenzando por la primera.

  • El lunes es solo la cadena de elementos con un M, por lo que la abreviatura más corta posible es M.

  • El martes comienza con T, pero también el jueves. Esto significa que probamos la cadena TU. Como ninguna otra secuencia comienza con eso, usamos TU.

  • El miércoles es W, el jueves es Thy el viernes es F.

Más ejemplos:

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.

Notas:

  • Realiza entradas y salidas de cualquier manera razonable.

  • Puede suponer que la entrada siempre será una matriz válida de cadenas.

  • Puede suponer que siempre habrá una solución, a diferencia del último caso de prueba.

  • Las cadenas solo consistirán en ASCII imprimible (o los caracteres imprimibles en su codificación)

  • Este es el código de golf, ¡por lo que ganan menos bytes!


Relacionado: 1 , 2 , 3
Sp3000

55
Posible duplicado de Golf Down the PPCG Usernames
Okx

2
No creo que sea un duplicado de ninguno de esos (aunque todos son bastante similares). En realidad, creo que este es probablemente el mejor desafío entre los cuatro; todos los demás tienen variantes que los hacen innecesariamente complicados.

2
¿Es importante el caso? En particular, el ejemplo del día de la semana usa una capital Upara el martes, pero en minúscula hpara el jueves.
Brian J

1
@Mego No edite mi publicación a menos que un moderador la marque como no duplicada
Julian Lachniet

Respuestas:


10

Retina , 29 bytes

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

La entrada y la salida son listas de cadenas separadas por salto de línea.

Pruébalo en línea! (Conjunto de pruebas con separación por comas para mayor comodidad).

Explicación

Esto simplemente coincide con todos los prefijos con una sola expresión regular y los imprime ( !). my sson los modificadores habituales de expresiones regulares para hacer ^que los inicios de línea .coincidan y los avances de línea coincidentes.

^(.+?)      # 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.

10

Python 2 , 87 86 bytes

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]

Pruébalo en línea!


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]por 85 bytes
Curtis Bechtel

reemplazar len(b)con 4**8guardar 2 bytes más, suponiendo que las cadenas no serán más de 65536 caracteres
Curtis Bechtel

8

JavaScript (ES6), 81 78 74 70 bytes

Toma la entrada como una matriz de cadenas.

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

Formateado y comentado

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

Casos de prueba


1
70 también, pero absolutamente otro: codegolf.stackexchange.com/a/113270/32091
Qwertiy

+1 para reduce.
Neil

6

Jalea , 14 bytes

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

Pruébalo en línea!

Cómo funciona

;\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.

6

Haskell , 48 bytes

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

Pruébalo en línea!

  • fes la función principal, tomar una lista de Stringsy devolver a String. Su definición es un atajo monádico para f a=map (a#) a.
  • a#xmira la cadena xy la lista ae intenta encontrar el prefijo más corto xque sea único en a. Si atiene un solo elemento, solo use la cadena vacía. Si aún ano es un solo elemento, corte el primer carácter de x, filtre y corte los elementos que acomienzan con el mismo carácter, luego repita.

4

Mathematica, 64 bytes

#&@@@StringCases[#,Shortest@x__/;Tr@Boole@StringStartsQ[#,x]<2]&

3

Jalea , 14 12 bytes

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

Pruébalo en línea!

Cómo funciona

ḣ€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.

Me pregunto, ¿por qué tienes 2 respuestas aquí? Me gustan los dos, pero me pregunto por qué tienes dos respuestas de Jelly aquí. :)
HyperNeutrino

Si tengo dos enfoques competitivos similares pero enfoques suficientemente diferentes, generalmente los publico en respuestas separadas.
Dennis

Buen punto. Sí, solo me preguntaba. :) Es una buena idea; Por lo general, no tengo más de un enfoque: P
HyperNeutrino

2

C ++ 11 (MinGW), 198 bytes

#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)<<" ";}}

Llamar con:

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

Agregar un voididentificador antes de la función también debería hacer que se compile en otros compiladores, agregando así 5 bytes a la longitud.


Debería ser void f..., no funciona de otra manera ... + 5 bytes, desafortunadamente. Hasta donde yo sé, las funciones necesitan especificadores de tipo en C ++
Mr. Xcoder

Además de eso, enfoque excepcional! Jugar golf en C / C ++ puede ser doloroso
Mr. Xcoder

@ Mr.Xcoder Sin embargo, compila en el compilador MinGW que estoy usando. Entonces es una extensión del compilador o un comportamiento indefinido.
Steadybox

Creo que se trata de la extensión del compilador, el CCG no funciona ...
Sr. Xcoder

1
Siempre que hay un entorno en el que funciona el código, que es válida
undergroundmonorail

2

Javascript ES6, 70 caracteres

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


2

PHP, 131 120 119 118 bytes

Gracias @ Jörg por 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)););

toma datos de los argumentos de la línea de comandos; imprime los resultados una línea cada uno.
Ejecutar -nro probarlo en línea .

  • puede fallar si la entrada contiene algo que comienza con -.
    +15 bytes para arreglar: reemplace el segundo $argvcon array_slice($argv,1).
  • produce advertencias en PHP 7.1; reemplace a&con ""<(+1 byte) para arreglar.
  • -12 bytes si la entrada no contiene caracteres especiales regex:
    inserte &($t.=$c)antes &&y reemplace ". preg_quote($t.=$c)."con $t.

Descompostura

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

versión no regex, 131 130 bytes

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

Reemplace el primero y el último a&con ""<(+2 bytes) para arreglar PHP 7.1.

Descompostura

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

Nota completamente poco interesante:
strstr($u,$t)==$uy 0===strpos($u,$t)tienen la misma longitud y el mismo resultado.


Utilice un carácter de nueva línea real ( 0x0A) en lugar de \n, guardará un byte;).
Blackhole

@Blackhole Gracias; Me olvidé de eso esta vez.
Tito

1

PHP, 127 bytes

no funciona con matrices no válidas

<?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 bytes

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

Versión en línea

151 bytes admite caracteres especiales

<?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 bytes

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

Esto fallará si la entrada contiene caracteres especiales regex. Tendría 113 bytes en lugar de 131 si no.
Titus

@Titus En este caso, podría agregar un preg_quoteMake solo 10 Bytes más
Jörg Hülsermann

También fallará si la entrada contiene 0. Pero puede guardar un byte con $i=+$s="".
Tito

y puede eliminar las count()-count()cosas: se garantiza que la entrada sea válida (-21 bytes). Creo que podría arreglar y jugar golf hasta 120 bytes. $_GETfue una buena idea!
Tito

@Titus No me he dado cuenta de que solo se permiten matrices válidas. Sí, fallaría si la cadena contiene un cero, pero esto había nacido una idea
Jörg Hülsermann

0

Clojure, 118 bytes

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

Esto funciona en prefijos de hasta 1e2la misma longitud pero el mismo número de bytes puede admitir hasta 1e9. ibucles longitudes de prefijos, Ses la secuencia de subcadenas de longitud i. El último forreemplaza aquellas subcadenas con las nilque ocurren con más frecuencia que una vez. La reducción mantiene el primer valor no nulo para cada cadena, lo malo orno es una función, así que tuve que ajustarlo.

En realidad, esto devuelve listas de listas de caracteres como ((\M) (\T \u) (\W) (\T \h) (\F)), pero supongo que es aceptable. Clojure es bastante detallado con cuerdas, y subsarrojaría a StringIndexOutOfBoundsExceptiondiferencia take.

Ejemplos completos:

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

0

SQL (sabor PostgreSQL 9.4), 219 bytes

Ahora para la respuesta más larga :) No creo que esto pueda vencer a Java. Intentaré afeitarme un poco más de esto. Con la esperanza de deshacerme de una de las consultas anidadas, pero no me gustan mis posibilidades.
Esto supone que hay una tabla que contiene las cadenas para trabajar. Como se trata de SQL, no se garantiza que el orden de devolución sea el mismo que el orden de la tabla y, en este caso, es poco probable. Si esto es un problema, lo eliminaré.

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


Explicación de violín SQL

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

La consulta más interna usa generate_seriesuna LATERALunión para crear filas para la cadena dividida en longitudes crecientes, de modo que 'uno' se convierte en 'o', 'en', 'uno'. El número de caracteres en la devolución también se mantiene.

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

Luego agregamos el número de registros que tienen el mismo resultado. Por ejemplo, 'f' de cuatro y cinco tiene 2, pero 'fo' y 'fi' tienen uno. La OVERdeclaración en SQL puede ser bastante poderosa. COUNT(*)sería la forma habitual, pero SUM(1)da el mismo resultado.

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

Luego clasificamos los resultados para cada entrada en función de la menor cantidad de repeticiones y caracteres. ROW_NUMBERfuncionaría aquí también, pero es más largo.

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

Finalmente seleccionamos el número de rango más bajo para cada palabra.



0

APL (Dyalog) , 27 bytes

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

Pruébalo en línea!

{ una función anónima, donde ⍵ representa el argumento ...

∘.( una tabla de funciones donde la función es

   el primer elemento de

   la lista booleana "argumento izquierdo comienza aquí en el argumento derecho?"

) donde están los argumentos correctos

 los argumentos

( y el argumento de la izquierda es

   una mesa con filas que consisten en

  ,/ prefijos de

  ¨ Cada uno de

   los argumentos

+/ suma a través (cuenta cuántos de los argumentos comienzan con este prefijo)

 dividir la tabla en una lista de filas

⍳⍨¨ en cada uno, encuentre la ubicación del primero

1 uno (es decir, el primer prefijo que solo encabeza un argumento)

↑¨⍨ para cada ubicación, toma tantos caracteres del elemento correspondiente de

 el argumento

} fin de la función anónima


0

PowerShell, 151 139 bytes

$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

Interesado si hay una mejor manera de hacer esto. Tuve que usar a foreach(sobre a |%) para poder realizar a breaken el bucle anidado sin etiquetarlo.

Editar: 2 campos de golf de AdmBorkBork


1
No he revisado el código directamente, pero seguramente podrías usarlo en -notinlugar de -not$x.contains($a)y en !($w...lugar de -not($w...guardar algunos bytes, ¿sí?
AdmBorkBork

0

APL, 26 bytes

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

Explicación:

  • ↓↑⍵: rellena cada cadena para que coincida con la longitud de la cadena más larga
  • ∘.(... )⍨: para cada posible par de cadenas, busque el prefijo compartido:
    • : desigualdad de matriz
    • : y
    • =: igualdad de elementos
    • ∧\: y-scan (mantener solo las coincidencias principales)
  • +/¨: suma cada vector en la tabla, dando la longitud de los prefijos compartidos
  • ⌈/: encuentra el valor máximo en cada columna
  • 1+: agregue uno, dando la cantidad de caracteres necesarios para mantener cada cadena única
  • ⍵↑¨⍨: toma tantos caracteres de cada cadena

Prueba:

      {⍵↑¨⍨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│
└─┴─┴─┴─┴─┴─┘

0

Q, 93 bytes

{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]}

Resuelto recursivamente, toma una cadena como entrada, obtiene los primeros n elementos de cada cadena con cada recursión. Si alguno de esos elementos no es único, los reemplaza con los primeros n + 1 elementos.

Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.