Abrevie uma matriz


26

Objetivo:

Dada uma matriz de cadeias, crie versões abreviadas de cada cadeia.

Especificação:

Para esse desafio, uma abreviação é os primeiros N caracteres de uma sequência. Para a cadeia abc: a, ab, e abcsão todas as abreviaturas válidas, enquanto bc, e acnão são.

Dada uma matriz de cadeias, queremos encontrar o menor conjunto de abreviações, de modo que, dada a entrada e qualquer abreviação, você possa determinar a qual item da entrada a referência se refere.

Exemplo:

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

Trabalhamos o nosso caminho através das cordas, começando pela primeira.

  • Monday é apenas a sequência de itens com um M, portanto, a menor abreviação possível é M.

  • Terça começa com T, mas quinta-feira também. Isso significa que tentamos a string TU. Como nenhuma outra string começa com isso, usamos TU.

  • Quarta é W, quinta é The sexta é F.

Mais exemplos:

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:

  • Você faz entrada e saída de qualquer maneira razoável.

  • Você pode assumir que a entrada sempre será uma matriz válida de strings.

  • Você pode assumir que sempre haverá uma solução, diferente do último caso de teste.

  • As strings consistem apenas em ASCII imprimível (ou nos caracteres imprimíveis na sua codificação)

  • Isso é código de golfe, e o menor número de bytes ganha!


Relacionado: 1 , 2 , 3
Sp3000

5
Possível duplicata do Golf Down the PPCG Usernames
Okx 18/17

2
Não acho que seja uma duplicata de nenhuma delas (embora todas sejam bastante parecidas). Na verdade, acho que esse é provavelmente o melhor desafio entre os quatro; os outros têm variantes que os tornam desnecessariamente complicados.

2
O caso é importante? Em particular, seu exemplo de dia da semana usa uma capital Upara terça-feira, mas uma minúscula hpara quinta-feira.
Brian J

1
@Mego não editar meu post a menos que um moderador irá marcá-lo como não sendo duplicado
Julian Lachniet

Respostas:


10

Retina , 29 bytes

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

Entrada e saída são listas de sequências separadas por avanço de linha.

Experimente online! (Conjunto de testes com separação por vírgula por conveniência.)

Explicação

Isso simplesmente combina todos os prefixos com um único regex e os imprime ( !). me ssão os modificadores de regex comuns para fazer o ^início da linha de .correspondência e os feeds de linha.

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

Experimente online!


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

substituindo len(b)com 4**8poupa mais 2 bytes, assumindo que as cordas não será mais do que 65536 caracteres
Curtis Bechtel

8

JavaScript (ES6), 81 78 74 70 bytes

Recebe entrada como uma matriz de seqüências de caracteres.

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

Formatado e 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 teste


1
70 também, mas absolutamente outro: codegolf.stackexchange.com/a/113270/32091
Qwertiy

+1 para reduce.
Neil

6

Gelatina , 14 bytes

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

Experimente online!

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

Experimente online!

  • fé a função principal, pegando uma lista de se Stringretornando a String. Sua definição é um atalho monádico para f a=map (a#) a.
  • a#xexamina a cadeia de caracteres xe a lista ae tenta encontrar o prefixo mais curto do xqual é único a. Se ativer um único elemento, basta usar a string vazia. Se aainda não é um elemento único, retire o primeiro caractere de x, filtre e remova os elementos de acomeçar com o mesmo caractere, e recorra novamente.

4

Mathematica, 64 bytes

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

3

Geléia , 14 12 bytes

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

Experimente online!

Como 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.

Basta saber, por que você tem 2 respostas aqui? Eu gosto dos dois, mas estou me perguntando por que você tem duas respostas de Jelly aqui. :)
HyperNeutrino

Se eu tenho duas abordagens competitivas semelhantes, mas suficientemente diferentes, geralmente as coloco em respostas separadas.
Dennis

Bom ponto. Sim, eu só estava pensando. :) Essa é uma boa ideia; Eu geralmente não têm mais do que uma abordagem: 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)<<" ";}}

Ligue para:

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

Adicionar voididentificador antes da função também deve compilar em outros compiladores, adicionando assim 5 bytes ao comprimento.


Deveria ser void f..., não funciona de outra forma ... + 5 bytes, infelizmente. Funções, tanto quanto eu sei, precisa digitar especificadores em C ++
Mr. Xcoder

Além disso, excelente abordagem! Golfe em C / C ++ pode ser doloroso
Mr. Xcoder

@ Mr.Xcoder Ele compila no compilador MinGW que estou usando. Portanto, é uma extensão do compilador ou um comportamento indefinido.
Steadybox

Eu acho que é sobre a extensão do compilador, em GCC ele não funciona ...
Mr. Xcoder

1
Enquanto há um ambiente em que o código funciona, é válido
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

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

recebe entrada de argumentos de linha de comando; imprime os resultados uma linha cada.
Corra com -nrou experimente online .

  • pode falhar se a entrada contiver algo que comece com -.
    +15 bytes para corrigir: substitua o segundo $argvpor array_slice($argv,1).
  • gera avisos no PHP 7.1; substitua a&por ""<(+1 byte) para corrigir.
  • -12 bytes se a entrada não contiver caracteres especiais regex:
    insira &($t.=$c)antes &&e substitua ". preg_quote($t.=$c)."por $t.

demolir

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

versão não 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);

Substitua o primeiro e o último a&por ""<(+2 bytes) para corrigir o PHP 7.1.

demolir

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 desinteressante:
strstr($u,$t)==$ue 0===strpos($u,$t)tem o mesmo comprimento e o mesmo resultado.


Use um caractere de nova linha real ( 0x0A) em vez de \n, ele salvará um byte;).
Blackhole

@Blackhole Obrigado; Eu esqueci disso dessa vez.
Titus

1

PHP, 127 bytes

não funciona com matrizes invá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);

Versão Online

151 bytes suporta caracteres especiais

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

Isso falhará se a entrada contiver caracteres especiais de regex. Eu teria 113 bytes em vez de 131, se não.
Titus

@Titus Neste caso, eu poderia adicionar um preg_quotefazer apenas 10 Bytes mais
Jörg Hülsermann

Também falhará se a entrada contiver 0. Mas você pode salvar um byte com $i=+$s="".
Titus

e você pode remover o count()-count()material: a entrada é garantida como válida (-21 bytes). Eu acho que eu poderia consertar e jogar golfe com até 120 bytes. $_GETfoi uma boa ideia!
Titus

@Titus Eu não percebi que apenas matrizes válidas são permitidas. Sim, seria um fracasso se a cadeia contém um zero, mas este tinha nascido uma idéia
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))))

Isso funciona em prefixos até o comprimento, 1e2mas a mesma contagem de bytes pode suportar até 1e9. iloops comprimentos de prefixos, Sé a sequência de substrings de comprimento i. O último forsubstitui as substrings pelas nilquais ocorrem mais frequentemente do que uma vez. A redução mantém o primeiro valor não nulo para cada sequência, uma pena que ornão é uma função, então tive que envolvê-la.

Na verdade, isso retorna listas de listas de caracteres como ((\M) (\T \u) (\W) (\T \h) (\F)), mas acho que é aceitável. Clojure é bastante detalhado com strings e subsjogaria StringIndexOutOfBoundsExceptiondiferente take.

Exemplos 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

Agora, a resposta mais longa :) Eu não acho que isso possa superar o Java. Vou tentar economizar um pouco mais disso. Esperando me livrar de uma das consultas aninhadas, mas não gostei das minhas chances.
Isso pressupõe que há uma tabela que contém as seqüências de caracteres a serem trabalhadas. Como se trata de SQL, não é garantido que a ordem do retorno seja igual à ordem da tabela e, nesse caso, improvável. Se este for um problema, eu excluirei.

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


Explicação do 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

A consulta mais interna usa generate_seriese uma LATERALjunção para criar linhas para a sequência dividida em comprimentos crescentes, para que 'one' se torne 'o', 'on', 'one'. O número de caracteres no retorno também é mantido.

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

Em seguida, adicionamos o número de registros que têm o mesmo resultado. Por exemplo, 'f' de quatro e cinco tem 2, mas 'fo' e 'fi' têm cada um. A OVERdeclaração no SQL pode ser bastante poderosa. COUNT(*)seria a maneira usual, mas SUM(1)dá o mesmo resultado.

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

Em seguida, classificamos os resultados para cada entrada com base no mínimo de repetições e caracteres. ROW_NUMBERfuncionaria aqui também, mas é mais longo.

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

Finalmente, selecionamos o número mais baixo para cada palavra.


0

Pure Bash , 146 bytes

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

Experimente online!


0

APL (Dyalog) , 27 bytes

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

Experimente online!

{ uma função anônima, onde ⍵ representa o argumento ...

∘.( uma tabela de funções em que a função é

   o primeiro elemento de

   a lista booleana "argumento esquerdo começa aqui no argumento certo?"

) onde os argumentos certos são

 os argumentadores

( e o argumento da esquerda é

   uma tabela com linhas consistindo em

  ,/ prefixos de

  ¨ cada um

   os argumentos

+/ soma entre (conta quantos dos argumentos estão com esse prefixo)

 dividir tabela em lista de linhas

⍳⍨¨ em cada um, encontre a localização do primeiro

1 um (ou seja, o primeiro prefixo que apenas encabeça um argumento)

↑¨⍨ para cada local, leva muitos caracteres do elemento correspondente de

 o argumento

} fim da função 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

Interessado se existe uma maneira melhor de fazer isso. Tinha que usar um foreach(sobre um |%) para poder executar um breakno loop aninhado sem rotulá-lo.

Edit: 2 golfe no AdmBorkBork


1
Eu não tenho ido através do código diretamente, mas certamente você pode usar -notinem vez de -not$x.contains($a)e !($w...em vez de -not($w...salvar alguns bytes, sim?
21817 AdmBorkBork

0

APL, 26 bytes

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

Explicação:

  • ↓↑⍵: insira cada sequência para corresponder ao comprimento da sequência mais longa
  • ∘.(... )⍨: para cada par possível de strings, encontre o prefixo compartilhado:
    • : desigualdade de matriz
    • : e
    • =: igualdade item a item
    • ∧\: and-scan (mantenha apenas as correspondências principais)
  • +/¨: soma cada vetor na tabela, fornecendo o comprimento dos prefixos compartilhados
  • ⌈/: encontre o valor máximo em cada coluna
  • 1+: adicione um, fornecendo a quantidade de caracteres necessária para manter cada sequência única
  • ⍵↑¨⍨: pegue tantos caracteres de cada string

Teste:

      {⍵↑¨⍨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]}

Resolvido recursivamente, recebe a string como entrada, obtém os primeiros n elementos de cada string com cada recursão. Se algum desses elementos não for exclusivo, ele será substituído pelos primeiros n + 1 elementos.

Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.