Gere atalhos de teclado para um menu

10

Atalhos de menu

Tradicionalmente, os menus do usuário são acessíveis por atalhos de teclado, como Alt + (a letter), ou simplesmente pressionando a letra, quando todas as caixas de texto estão fora de foco ( estilo gmail ).

Sua tarefa

Dadas as entradas do menu como uma entrada, sua tarefa é conceder a cada entrada do menu uma letra de atalho adequada.

Escreva uma função ou um programa que aceite um conjunto de palavras - as entradas do menu (como uma matriz de seqüências de caracteres ou seu idioma equivalente) e retorne um dicionário ou um mapa de hash de uma única letra para uma entrada do menu.

Você pode usar um parâmetro e retornar um valor ou usar o STDIN e enviar seus resultados para STDOUT. Você não tem permissão para assumir que uma variável global / escopo já está preenchida com a entrada.

Algoritmo para determinar a letra correta

  • Basicamente, é a primeira letra disponível da palavra. Veja suposições e exemplos abaixo.
  • Caso todas as letras da entrada não estejam disponíveis, o atalho será (a letter) + (a number). Qual letra você escolhe da entrada é arbitrária. O número deve começar de 0 e ser incrementado por 1 - de modo que todos os atalhos sejam exclusivos. Veja o terceiro exemplo abaixo.

Premissas

  • A entrada será um conjunto, ou seja, sem repetições, cada entrada é única.
  • O comprimento da entrada pode ser qualquer número inteiro não negativo (até MAX_INT do seu idioma).
  • Distinção entre maiúsculas e minúsculas: a entrada diferencia maiúsculas de minúsculas (mas permanecerá exclusiva ao ignorar maiúsculas e minúsculas). Os resultados devem conter as entradas originais com sua caixa original. No entanto, as letras de atalho de saída não diferenciam maiúsculas de minúsculas.
  • Todas as palavras de entrada não terminam com números.
  • Nenhuma "entrada ruim" será testada. "Entrada incorreta" é tal que você precisa incrementar o contador de uma determinada letra mais de 10 vezes.

Exemplos

Os exemplos abaixo estão em JSON, mas você pode usar o idioma equivalente para uma matriz e um dicionário ou, caso esteja usando STD I / O, qualquer formato legível para sua entrada e saída (como csv ou até espaço). valores separados).

1

Input:  ['File', 'Edit', 'View', 'Help']
Output: {f:'File', e:'Edit', v:'View', h:'Help'}

2)

Input:  ['Foo', 'Bar', 'FooBar', 'FooBars']
Output: {f:'Foo', b:'Bar', o:'FooBar', a:'FooBars'}

3)

Input:  ['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba']
Output: {a:'a', b:'b', a0:'aa', b0:'bb', q:'bbq', b1:'bbb', b2:'ba'}

Condições vencedoras

O menor código vence. Somente ASCII é permitido.

Jacob
fonte
"a" já está ocupado pela primeira entrada. Portanto, para "aa", uma vez que as duas letras já estão ocupadas, ele recebe a0. Mesmo com b0-b2.
mattacular
O que acontece quando você fica sem números?
nderscore
@nderscore Isso é realmente necessário?
seequ
Deve ['ab', 'a']dar {a:'ab', a0:'a'}ou {b:'ab', a:'a'}?
Adám
@ Adám ambos são aceitáveis. Seria mais fácil implementar o primeiro, uma vez que você varre a matriz de entrada de maneira ordenada, mas se, por algum motivo, você preferir o último - vá em frente.
Jacob

Respostas:

4

Javascript ( ES6 ) 106 105 100

Essa função recebe entrada como uma matriz e gera um objeto javascript.

f=i=>i.map(a=>{for(b of c=a.toLowerCase(d=0)+d+123456789)d<!o[e=b>=0?c[0]+b:b]&&(o[d=e]=a)},o={})&&o

Resultados:

f(['File', 'Edit', 'View', 'Help']);
// {"f":"File","e":"Edit","v":"View","h":"Help"}

f(['Foo', 'Bar', 'FooBar', 'FooBars']);
// {"f":"Foo","b":"Bar","o":"FooBar","a":"FooBars"}

f(['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba']);
// {"a":"a","b":"b","a0":"aa","b0":"bb","q":"bbq","b1":"bbb","b2":"ba"}

Sem Golfe / Comentado:

f=i=>{
  o={};                                        // initialize an object for output
  i.map(a=>                                    // loop through all values in input
    for(b of c=a.toLowerCase(d=0)+d+123456789) // loop through all characters of the string with 0123456789 appended to the end
                                               // and initialize d as 0 to be used as a flag 
      e=b>=0?c[0]+b:b                          // if b is a number, set e to the first character + the number, otherwise b
      if(d<!o[e])                              // if the flag hasn't been triggered and o doesn't have a property e
        o[d=e]=a                               // then store the value at e and trigger the d flag
  )
  return o                                     // return the output object
}
nderscore
fonte
Isso é lindo. Pode falhar com a entrada do mal ['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaaa', 'aaaaaaaaaaaa'], mas acho que podemos ignorar esses casos extremos, não podemos?
Jacob
@ Jacob E o que acontece quando atingimos 11? Você não pode pressionar a tecla de um duas vezes em um atalho de teclado: P
nderscore
Você tem um ponto lá (embora isso seja possível, dada uma implementação que aguarda até o final do pressionamento de tecla (200 ms ou mais)). De qualquer forma, acrescentarei às suposições que nenhuma entrada maligna será testada.
Jacob
2

Python 2.x - 176 170157 114 bytes

Abordagem muito simples, mas alguém tem que começar o jogo.

r={}
for i in input():a=list(i.upper());r[([c for c in a+[a[0]+`x`for x in range(10)]if c not in r])[0]]=i
print r

Edit 1: Reversed the checking operation and made it set the result only once.
Edit 2: Removed branching.
Edit 3: Removed unnecessary dictionary. (thanks to the added assumption)

Exemplos:

Input:  ['File', 'Edit', 'View', 'Help']
Output: {'H': 'Help', 'V': 'View', 'E': 'Edit', 'F': 'File'}

Input:  ['Foo', 'Bar', 'FooBar', 'FooBars']
Output: {'A': 'FooBars', 'B': 'Bar', 'O': 'FooBar', 'F': 'Foo'}

Input:  ['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba']
Output: {'A': 'a', 'B': 'b', 'Q': 'bbq', 'A0': 'aa', 'B0': 'bb', 'B1': 'bbb', 'B2': 'ba'}

Eu acho que a única explicação necessária é o código não destruído. (Esta é realmente a versão original)

items = input() # ['File', 'Edit', 'View', 'Help']
chars = map(chr,range(65,91))
numbers = {}.fromkeys(chars,0)
result = {}
for item in items:
    try:
        key = [c for c in item.upper() if c in chars][0] # causes an exception when no items match
        result[key] = item
        chars.remove(key)
    except:
        key = item[0].upper()
        result[key+`numbers[key]`] = item
        numbers[key] += 1
print result
seequ
fonte
Eu tenho que dizer humilde obrigado a @Jacob. O formato de entrada é ótimo.
seequ
2

JavaScript (ECMAScript 6) - 107 caracteres

f=a=>(o={},p={},[o[[c for(c of l=w.toLowerCase())if(!o[c])][0]||(k=l[0])+(p[k]=p[k]+1|0)]=w for(w of a)],o)

Explicação:

f=a=>(
  o={},                              // The dictionary to output
  p={},                              // Stores record of numbers appended after duplicate
                                     // menu keys
  [                                  // Use array comprehension for each word w of input a
   (unmatchedCharacters
     =[c                             // Use array comprehension for each character c of
      for(c of l=w.toLowerCase())    //   the lower case of word w but only get
      if(!o[c])                      //   those characters which are not already a key in o.
     ],
    key=unmatchedCharacters[0]       // Take the first of those characters
     ||                              // Or if all characters are already in o
     (k=l[0])                        // Take the first character of the lower-case word
     +(p[k]=p[k]+1|0),               //   concatenated with the increment of the digit stored
                                     //   in p (or zero). 
   o[key]=w)                         // Set o to map from this key to the word
   for(w of a)
  ],
  o)                                 // return o

Testes:

f(['File', 'Edit', 'View', 'Help']);
{f: "File", e: "Edit", v: "View", h: "Help"}

f(['Foo', 'Bar', 'FooBar', 'FooBars']);
{f: "Foo", b: "Bar", o: "FooBar", a: "FooBars"}

f(['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba']);
{a: "a", b: "b", a0: "aa", b0: "bb", q: "bbq", b1: "bbb", b2: "ba"}
MT0
fonte
1

PHP> = 5.4 - 149 caracteres

De acordo com os padrões do PHP (insira sniggers aqui) , a entrada não é válida como JSON, pois ela é usada em 'vez de ", então eu tenho sido um pouco atrevido e estou usando a Entrada como uma declaração de variável real:

<?
$i = ['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba'];
$c=[];foreach($i as$w){foreach(str_split($w) as$j)if(!$c[$j]){$x=$j;goto f;}$n=0;do{$x=$w[0].$n++;}while($c[$x]);f:$c[$x]=$w;}echo json_encode($c);

Usando os exemplos:

Input:  ['File', 'Edit', 'View', 'Help']
Output: {"F":"File","E":"Edit","V":"View","H":"Help"}

Input:  ['Foo', 'Bar', 'FooBar', 'FooBars']
Output: {"F":"Foo","B":"Bar","o":"FooBar","a":"FooBars"}

Input:  ['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba']
Output: {"a":"a","b":"b","a0":"aa","b0":"bb","q":"bbq","b1":"bbb","b2":"ba"}

Não-golfificado é bem básico:

<?
$i = ['a', 'b', 'aa', 'bb', 'bbq', 'bbb', 'ba'];
$c = [];
foreach($i as $w)
{
    foreach(str_split($w) as $j)
        if(!$c[$j])
        {
            $x = $j;
            goto f;
        }
    $n = 0;
    do
    {
        $x = $w[0] . $n++;
    }
    while($c[$x]);
    f: $c[$x] = $w;
}
echo json_encode($c);
MrLore
fonte
PHP tem declarações de salto? Isso é tão ... anos 90.
see
2
Você não precisa seguir o JSON, forneci apenas os exemplos em JSON, mas, conforme declarado na pergunta, você pode escolher qualquer formato legível para saída ou usar seu idioma equivalente para um Dicionário. (Você pode salvar 13 caracteres removendo a json_encodechamada).
Jacob
echonão funciona com matrizes; mas print_r($c);faria isso, economizando 9 bytes.
Titus
Mas isso não faz distinção entre maiúsculas e minúsculas. str_split(strtoupper($w))e ucfirst($w[0])pode resolver isso (+21); ou $s=strtoupper($w);(+18)
Tito
1

PowerShell , 91 83 bytes

$r=@{}
$args|%{$r[($_|% *wer|% t*y|%{$c=$_;,''+0..9|%{$c+$_}|?{!$r.$_}})[0]]=$_}
$r

Experimente online!

Emite uma exceção se um atalho adequado não for encontrado.

Desenrolado:

$result=@{}
$args|%{
    $shortcuts = $_|% toLower|% toCharArray|%{
        $c=$_
        ,''+0..9|%{$c+$_}|?{!$result.$_}    # output shortcuts are not exist in the result
    }
    $properShortcut = $shortcuts[0]         # throws an exception if a proper shortcut not found
    $result[$properShortcut]=$_
}
$result
confuso
fonte
0

PHP, 153 bytes

for($c=[];$w=trim(fgets(STDIN));$c[reset(array_diff(str_split($s),array_keys($c)))?:$y]=$w){$s=strtoupper($w);for($n=0;$c[$y=$s[0].$n++];);}print_r($c);

executar com php-r '<code>' <<EOF+ Enter + <word1>+ Enter + <word2>+ Enter + ... + EOF+ Enter

trabalhando no argv por 155 bytes :

$c=[];foreach($argv as$i=>$w)if($i){$s=strtoupper($w);for($n=0;$c[$y=$s[0].$n++];);$c[reset(array_diff(str_split($s),array_keys($c)))?:$y]=$w;}print_r($c);

correr com php -r '<code>' <word1> <word2> ...

(-13 bytes com um global definido: em foreach($i as$w)vez de foreach($argv as$i=>$w)if($i))

Titus
fonte