Implementar conclusão da guia

31

O preenchimento de tabulação é um recurso útil que conclui automaticamente parcialmente os comandos gravados. Você vai implementá-lo.

Por exemplo, se os comandos disponíveis fossem ['apply','apple','apple pie','eat'], aseria concluído applcomo, como todos os comandos ainiciados com appl.

Entrada / Saída

Você precisa inserir uma sequência A e um conjunto de seqüências B.

Você precisa gerar o prefixo comum mais longo de todos os B que começa com A.

  • Se nenhuma das opções começar com A, retorne A
  • Você pode assumir que B não é vazio e que todas as cadeias de caracteres são vazias
  • Você não pode assumir que qualquer uma das opções comece com A, nem que o prefixo comum seja maior que A
  • Você pode fazer distinção entre maiúsculas e minúsculas ou não.
  • Você só precisa lidar com ASCII imprimível
  • Built-ins que explicitamente executam essa tarefa são permitidos

Casos de teste:

'a'       ['apply','apple','apple pie','eat'] => 'appl'
'a'       ['apple pie']                       => 'apple pie'
'apple'   ['eat','dine']                      => 'apple'
'program' ['programa','programb']             => 'program'
'*%a('    ['*%a()-T>','*%a()-T<','@Da^n&']    => '*%a()-T'
'a'       ['abs','absolute','answer']         => 'a'
'a'       ['a','abs']                         => 'a'
'one to'  ['one to one','one to many']        => 'one to '

Observe o espaço à direita no último caso de teste

Este é um , portanto, faça suas respostas o mais curto possível!

Nathan Merrill
fonte
Você poderia adicionar um exemplo com caracteres ASCII imprimíveis e não alfabéticos para posteridade?
Conor O'Brien
Mais exemplos com caracteres não alfabéticos não poderiam prejudicar. Acabei de excluir minha resposta porque percebi que ela se rompeu com entradas contendo \​or '.
Dennis
Não sei como representar 'em um exemplo. Se eu usar "para as strings, as strings são diferentes de outros exemplos.
Nathan Merrill
Esse é exatamente o problema que minha resposta teve. : P
Dennis

Respostas:

10

JavaScript (ES6), 75 bytes

(s,a)=>/^(.*).*(\n\1.*)*$/.exec(a.filter(e=>e.startsWith(s)).join`
`)[1]||s

Explicação: Filtra todos os prefixos correspondentes e junta-se a novas linhas e correspondências em uma regex que encontra o prefixo comum mais longo de todas as linhas. Se não houver prefixos, o regex retornará uma string vazia. Nesse caso, simplesmente retornamos a string original.

Neil
fonte
É possível substituir e.startsWith(s)com e.match("^"+s)um byte fora Currying irá poupar uma outra
Shaun H
@ ShaunH Não posso usar matchcom ASCII imprimível arbitrário.
Neil
Oh regex certo e caracteres de controle. você ainda pode curry (s,a)=>paras=>a=>
Shaun H #
7

Geléia , 14 12 bytes

ḣJ$€ċÐff\ṪṪȯ

Experimente online! ou verifique todos os casos de teste .

Como funciona

ḣJ$€ċÐff\ṪṪȯ  Main link. Left argument: B. Right argument: A

  $€          Convert the two links to the left into a monadic chain and apply it
              to each string s in B.
 J              Generate the indices of s, i.e., [1, ..., len(s)].
ḣ               Head; for each index i, take the first i characters of s.
              This generates the prefixes of all strings in B.
     Ðf       Filter; keep prefixes for which the link to the left returns 1.
   ċ            Count the number of times A appears in the prefixes of that string.
       f\     Do a cumulative (i.e., keeping all intermediate values) reduce by
              filter, keeping only common prefixes. f/ is a more obvious choice,
              but it errors on an empty array, i.e., when A isn't a prefix of any
              string in B.
         Ṫ    Tail; take the last prefix array (if any) or return 0.
          Ṫ   Tail; take the last common prefix (if any) or return 0.
           ȯ  Logical OR (flat); replace 0 with A, leave strings untouched.
Dennis
fonte
6

Pitão, 14 13 bytes

Obrigado a @isaacg por -1 byte

.xe@F/#z._MQz

Um programa que pega a lista de seqüências de caracteres e, em seguida, a seqüência de caracteres em STDIN e imprime o resultado.

Verifique todos os casos de teste

Como funciona

.xe@F/#z._MQz  Program. Inputs: Q, z
        ._MQ   Map prefixes over Q
     /#z       Filter that by count(z)>0, removing the prefixes corresponding to elements
               in Q that do not start with z
   @F          Fold intersection over that. This yields all the common prefixes
  e            Yield the last element of that, giving the longest common prefix, since the
               prefixes are already sorted by length
.x             But if that throws an exception since no elements of Q start with z:
            z  Yield z instead
               Implicitly print
TheBikingViking
fonte
1
f}zT=>/#z
isaacg 23/09/16
5

PowerShell v3 +, 112 bytes

param($a,$b)if($c=@($b-like"$a*")){([char[]]$c[0]|%{($i+="$_")}|?{($c-like"$_*").count-eq$c.count})[-1]}else{$a}

Recebe a entrada como uma sequência $ae uma matriz de sequências $b. Usa o -likeoperador para extrair esses elementos $b(sem diferenciação de maiúsculas e minúsculas) $a, convertê-los explicitamente como uma matriz @(...)(já que o resultado pode ser uma correspondência como escalar, caso em que a indexação falha posteriormente) e armazenar essa matriz $c.

Isso forma a ifcláusula. Se não houver nada $c(isto é, nada começa com $a, então a matriz está vazia), em seguida, imprima $acom else. De outra forma ...

Elencamos o primeiro elemento $ccomo char-array e percorremos cada elemento, concatenando $ias strings com o anterior e colocando as strings no pipeline por meio de parênteses de encapsulamento. Aqueles são filtrados através de |?{...}(a Where-Objectcláusula) para verificar se o .countde $cé -equal ao .countde coisas em $cque estão -likea substring (ou seja, o substring combina com tudo em $ c). Como estamos construindo nossas substrings da ordem do menor para o maior, precisamos da última [-1]das seqüências resultantes.

Casos de teste

PS C:\Tools\Scripts\golfing> $tests=@('a',@('apply','apple','apple pie','eat')),@('a',@('apple pie')),@('apple',@('eat','dine')),@('program',@('programa','programb')),@('one to',@('one to one','one to many')),@('*%a(',@('*%a()-T>', '*%a()-T<', '@Da^n&'))

PS C:\Tools\Scripts\golfing> $tests|%{""+$_[0]+" ("+($_[1]-join',')+") -> "+(.\implement-tab-completion.ps1 $_[0] $_[1])}
a (apply,apple,apple pie,eat) -> appl
a (apple pie) -> apple pie
apple (eat,dine) -> apple
program (programa,programb) -> program
one to (one to one,one to many) -> one to 
*%a( (*%a()-T>,*%a()-T<,@Da^n&) -> *%a()-T
AdmBorkBork
fonte
4

Python 2, 122 bytes

s=input();l=[x for x in input()if x[:len(s)]==s]or[s];i=len(l[0])
while len(l)>1:i-=1;l=set(x[:i]for x in l)
print l.pop()

Programa completo; usa string e lista de stdin exatamente como fornecido nos exemplos, exceto que as entradas devem estar em linhas separadas.

Verifique todos os casos de teste

DLosc
fonte
Por que ao l.pop()invés de l[-1]?
Cyoce 23/09/16
@ Cyc Porque lgeralmente é um setnesse ponto, o que não permite a indexação (sendo desordenada). (Felizmente, ambos os conjuntos e listas de apoio pop().)
DLosc
3

Perl, 54 bytes

Inclui +2 para -Xp(pode ser combinado com -e) e +3 para -i(não pode ser combinado)

Forneça um dicionário sobre STDIN e a palavra após a -iopção, por exemplo:

perl -ia -Xpe '/^\Q$^I\E.*?(?{$F[$a{$&}++]=$&})^/}{$_=pop@F||$^I'
apply
apple
apple pie
eat
^D

Apenas o código:

/^\Q$^I\E.*?(?{$F[$a{$&}++]=$&})^/}{$_=pop@F||$^I
Ton Hospel
fonte
3

Perl, 61 bytes

Inclui +2 para -0p

Execute com a primeira palavra seguida pelas palavras do dicionário em STDIN:

tabcompletion.pl
a
apply
apple
apple pie
eat
^D

tabcompletion.pl:

#!/usr/bin/perl -0p
/^(.+)
((?!\1).*
)*(\1.*).*
((?!\1).*
|\3.*
)*$|
/;$_=$3||$`
Ton Hospel
fonte
2

Python 2, 112 bytes

lambda n,h:[a.pop()for a in[{s[:-i]for s in h if s.find(n)==0}for i in range(-len(`h`),0)]+[{n}]if len(a)==1][0]
Lynn
fonte
2

Haskell, 67 bytes

(a:b)?(c:d)|a==c=a:(b?d)
_?_=""
s%l=foldr1(?)$max[s][x|x<-l,x?s==s]

A função auxiliar ?encontra o prefixo comum mais longo de duas cadeias, recursivamente, obtendo o primeiro caractere, desde que seja o mesmo para as duas cadeias e as cadeias não estejam vazias.

A principal função %primeira mantém apenas as cordas na lista que começa com o dado um s, verificado pela maior prefixo comum com ssendo s. Para lidar com a inexistência de competições válidas, ele adiciona sum resultado vazio via max. Em seguida, ele encontra o maior prefixo comum desses ao dobrar a função binária ?.

xnor
fonte
2

Python 2, 75 bytes

import os
lambda s,x:os.path.commonprefix([t for t in x if s<=t<s+'ÿ'])or s

Agradecemos a @xnor por sugerir o built-in, originalmente usado por @BetaDecay nesta resposta .

Para fins de pontuação, ÿpode ser substituído por um byte DEL. Teste em Ideone .

Dennis
fonte
1

D, 88 bytes

S f(S)(S p,S[]q){try p=q.filter!(a=>a.startsWith(p)).fold!commonPrefix;catch{}return p;}

Uso:

assert(f("a", ["apply","apple","apple pie","eat"]) ==  "appl");

O código simplesmente remove todos os elementos dos qquais não começa p, depois calcula a maior subsequência inicial comum dos elementos restantes.

Os parâmetros de modelo nos salvam duas repetições de stringe uma de auto. O uso indevido da exceção permite evitar a variável temporária e condicional que seriam necessárias para lidar com o caso em que nenhum elemento qinicial p.

Raio
fonte
1

Python 2, 107 102 bytes

s,x=input();r='';q=1
for c in zip(*[t for t in x if s<=t<s+'ÿ']):q/=len(set(c));r+=c[0]*q
print r or s

Para fins de pontuação, ÿpode ser substituído por um byte DEL. Teste em Ideone .

Obrigado a @xnor por salvar 5 bytes!

Dennis
fonte
Com os.path.commonprefix o Beta Decay encontrado , você pode fazer o trabalho para você.
xnor
Uau, isso economiza muitos bytes. Tem certeza de que não deseja postar isso sozinho?
Dennis
Eu não me sentiria bem ao publicá-lo, pois é apenas a idéia do Beta Decay combinada com a sua resposta.
Xnor
Para sua solução, parece um pouco mais curto iterar for c in ...diretamente e terminar com erro após a impressão if len(set(c))>1:print r or s;_.
xnor
Eu acho que falharia se x é uma matriz singleton.
Dennis
1

PHP, 167 160 157 152 bytes

<?for($r=preg_grep("$^".preg_quote($s=$_GET[s])."$",$a=$_GET[a]);$r[0]>$s&&preg_grep("$^".preg_quote($t=$s.$r[0][strlen($s)])."$",$a)==$r;)$s=$t;echo$s;

Eu poderia economizar mais 3 bytes atribuindo variáveis ​​com preg_grepe preg_quote, mas eh.

demolir

for(
    // find items in $a that start with $s
    $r=preg_grep("$^".preg_quote($s=$_GET[s])."$",$a=$_GET[a]);
    // while the first match is longer than $s
    $r[0]>$s
    // and appending the next character of the first match
    &&preg_grep("$^".preg_quote($t=$s.$r[0][strlen($s)])."$",$a)
    // does not change the matches
    ==$r
;)
    // keep appending
    $s=$t;
return$s;
Titus
fonte
1

PHP, 156 bytes

com muita ajuda de Titus Obrigado

<?foreach($_GET[t]as$v)if(strstr($v,$s=$_GET[s])==$v)$r[]=$z=$v;for(;$i++<strlen($z);){$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;}echo$s;

PHP, 199 bytes

32 bytes salvos por Titus com array_unique

<?foreach($_GET[t]as$v)if(strstr($v,$s=$_GET[s])==$v)$r[]=$v;for(;$i++<strlen($r[0]);$a=[]){foreach($r as$x)$a[]=substr($x,0,$i);if(count($r)==count($a)&count(array_unique($a))<2)$s=$a[0];}echo$s;

Eu sei que a solução Regex de Titus foi mais curta até que Titus me ajudasse a melhorar meu caminho. Talvez a maneira que eu encontrei seja interessante para você

Jörg Hülsermann
fonte
1
1) Replace $z with $s to fix the apple, [eat,dine] case. 2) $l= is obsolete; You don´t use that variable. (-2) 3) $i++<$m is shorter than ++$i<=$m. (-1) 4) substr($x,0,$i); is shorter than str_split($x,$i)[0]. (-3) 5) You can put $r[]=$v inside the strlen. (-5)
Titus
1
6) <2 is shorter than ==1. (-1) 7) You could use strstr in the first loop: strstr($v,$s)==$v. (-3)
Titus
1
Let me rephrase it: 5) You can combine $r[]=$v;$m=max($m,strlen($v)); to $m=max($m,strlen($r[]=$v)); and drop the curlys. This doesn´t touch the condition.
Titus
1
On second thought, you don´t need $m at all. All you need is something that is >= the minimum length of the replacements. The new 5) Replace {$r[]=$v;$m=max($m,strlen($v));} with $r[]=$v;} and <$m with <strlen($r[0]) (-13)
Titus
1
Great! And I just found another golf: 9) $r[]=$z=$v; in the first loop and {$s=substr($z,0,$i);foreach($r as$x)if($x[$i]!=$z[$i])break 2;} for the second (-3)
Titus
1

Retina, 60 bytes

^(.*)(\n(?!\1).*)*(\n(\1.*)).*(\n((?!\1)|\4).*)*$
$4
s`\n.*

The trailing new line is significant. Takes input as the string on a line and then each word on a separate line (but no trailing newline!). Works in a similar way to my JavaScript answer by matching the longest common prefix of all lines that begin with the string on the first line. If it doesn't find one then it simply deletes all the words.

Neil
fonte
0

Scala, 119 bytes

def f(s:String,a:Seq[Char]*)=a filter(_ startsWith s)reduceOption(_ zip _ takeWhile(t=>t._1==t._2)map(_._1))getOrElse s

Ungolfed:

def tabComplete(input: String, options: Seq[Char]*) = {
  options.
  filter((x: String) => x.startsWith(input)).
  reduceOption((x: Seq[Char], y: Seq[Char]) =>
    x.zip(y).
    takeWhile((t: (Char, Char)) => t._1 == t._2).
    map((t: (Char, Char)) => t._1)
  ).getOrElse(input)
}

Explanation:

def g(s:String,a:Seq[Char]*)= //define a method g with a string and a vararg array of strings as parameter
  a filter(_ startsWith s)    //filter the options to contains only elements starting with the input
  reduceOption(               //if the filtered array is nonempty, reduce it: 
    _ zip _                     //zip two elements together
    takeWhile(t=>t._1==t._2)    //take the tuples while they contain the same char
    map(_._1)                   //take the first element from each tuple
  )getOrElse s                //else return the input
corvus_192
fonte
0

05AB1E, 14 bytes

ʒIÅ?}€ηøʒË}‚˜θ

Try it online or verify all test cases.

Explanation:

ʒ   }           # Filter the (implicit) input-list
 IÅ?            #  Does it start with the (second) input-string
                #   i.e. ["codex","bla","codegolf"] and "c" → ["codex","codegolf"]
     €η         # Then take the prefixes of every remaining string
                #  → [["c","co","cod","code","codex"],
                #     ["c","co","cod","code","codeg","codego","codegol","codegolf"]]
       ø        # Zip/transpose; swapping rows/columns
                #  → [["c","c"],["co","co"],["cod","cod"],["code","code"],["codex","codeg"]]
        ʒ }     # Filter:
         Ë      #  Only keep sublists which only contain the same substrings
                #   → [["c","c"],["co","co"],["cod","cod"],["code","code"]]
               # Pair it with the (second implicit) input
                #  → ["c",["c","c"],["co","co"],["cod","cod"],["code","code"]]
                # (workaround if nothing in the input-list starts with the input-string)
            ˜   # Flatten this list
                #  → ["c","c","c","co","co","cod","cod","code","code"]
             θ  # And only leave the last item (which is output implicitly as result)
                #  → "code"
Kevin Cruijssen
fonte
0

Gaia, 12 bytes

e…¦&⊢…Ė⁇_+ₔ)

Try it online!

Takes input as B, then A.

e		| eval B as list of strings
 …¦		| take prefixes of each string
   &⊢		| reduce by set intersection
     …		| take list prefixes of each.
      Ė⁇	| Keep only those with A as an element
	_	| flatten
	 +ₔ	| add A to the beginning of the list
	   )	| take the last element
Giuseppe
fonte