Générer des raccourcis clavier pour un menu

10

Raccourcis du menu

Traditionnellement, les menus utilisateur sont accessibles par des raccourcis clavier, tels que Alt + (a letter), ou même simplement en tapant la lettre lorsque toutes les zones de texte sont floues ( style gmail ).

Ta tâche

Étant donné les entrées de menu en entrée, votre tâche consiste à attribuer à chaque entrée de menu une lettre de raccourci appropriée.

Écrivez une fonction ou un programme qui accepte un ensemble de mots - les entrées de menu (sous forme de tableau de chaînes ou l'équivalent de votre langue) et renvoie un dictionnaire ou une table de hachage, d'une seule lettre à une entrée de menu.

Vous pouvez soit utiliser un paramètre et renvoyer une valeur, soit utiliser le STDIN et envoyer vos résultats à STDOUT. Vous n'êtes pas autorisé à supposer qu'une variable globale / portée est déjà remplie avec l'entrée.

Algorithme pour déterminer la bonne lettre

  • Fondamentalement, c'est la première lettre disponible du mot. Voir les hypothèses et exemples ci-dessous.
  • Si toutes les lettres de l'entrée ne sont pas disponibles, le raccourci sera (a letter) + (a number). La lettre que vous choisissez dans l'entrée est arbitraire. Le nombre doit commencer à 0 et être incrémenté de 1, de sorte que tous les raccourcis soient uniques. Voir le troisième exemple ci-dessous.

Hypothèses

  • L'entrée sera un ensemble, c'est-à-dire sans répétition, chaque entrée est unique.
  • La longueur de l'entrée peut être n'importe quel entier non négatif (jusqu'à MAX_INT de votre langue).
  • Sensibilité à la casse: L'entrée est sensible à la casse, (mais restera unique en ignorant la casse). Les résultats doivent contenir les entrées originales avec leur boîtier d'origine. Cependant, les lettres de raccourci de sortie ne sont pas sensibles à la casse.
  • Tous les mots saisis ne se termineront pas par des chiffres.
  • Aucune "mauvaise entrée" ne sera testée. "L'entrée du mal" est telle que vous devez incrémenter le compteur d'une certaine lettre plus de 10 fois.

Exemples

Les exemples ci-dessous sont en JSON, mais vous pouvez utiliser votre équivalent de langue pour un tableau et un dictionnaire, ou - dans le cas où vous utilisez des E / S STD - n'importe quel format lisible pour vos entrées et sorties (comme csv, ou même espace- valeurs séparées).

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

Conditions gagnantes

Le code le plus court gagne. Seul ASCII est autorisé.

Jacob
la source
"a" est déjà pris par la première entrée. Donc pour "aa" puisque ses deux lettres sont déjà occupées, il obtient a0. Idem avec b0-b2.
mattacular
Que se passe-t-il lorsque vous manquez de chiffres?
nderscore
@nderscore Est-ce vraiment nécessaire?
seequ
Devrait ['ab', 'a']donner {a:'ab', a0:'a'}ou {b:'ab', a:'a'}?
Adám
@ Adám les deux sont acceptables. Il serait plus facile de mettre en œuvre le premier puisque vous numérisez le tableau d'entrée de manière ordonnée, mais si pour une raison quelconque vous préférez le second, allez-y.
Jacob

Réponses:

4

Javascript ( ES6 ) 106 105 100

Cette fonction prend l'entrée comme un tableau et génère un objet 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

Résultats:

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

Non golfé / commenté:

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
la source
C'est beau. Cela peut échouer pour la mauvaise entrée ['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaaa', 'aaaaaaaaaaaa'], mais je pense que nous pouvons ignorer ces cas extrêmes, n'est-ce pas?
Jacob
@Jacob Et que se passe-t-il lorsque nous frappons 11? Vous ne pouvez pas appuyer deux fois sur la même touche dans un raccourci clavier: P
nderscore
Vous avez un point là (bien que cela puisse être possible, étant donné une implémentation qui attend la fin des frappes (200 ms environ)). Quoi qu'il en soit, j'ajouterai aux hypothèses qu'aucune mauvaise entrée ne sera testée.
Jacob
2

Python 2.x - 176170157114 octets

Approche très simple, mais quelqu'un doit lancer le jeu.

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)

Exemples:

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

Je pense que la seule explication requise est le code non golfé. (Il s'agit en fait de la version originale)

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
la source
Je dois dire un humble merci à @Jacob. Le format d'entrée est tout simplement génial.
seequ
2

JavaScript (ECMAScript 6) - 107 caractères

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)

Explication:

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

Tests:

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
la source
1

PHP> = 5,4 - 149 caractères

Selon les normes PHP (insérez des sniggers ici) , l'entrée n'est pas JSON valide car elle utilise à la 'place de ", donc j'ai été un peu effronté et j'utilise l'entrée comme une déclaration de variable réelle:

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

En utilisant les exemples:

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

Non golfifié, c'est assez basique:

<?
$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
la source
PHP a des déclarations de saut? C'est tellement ... 90's.
seequ
2
Vous n'avez pas à vous en tenir à JSON, je n'ai fourni que les exemples en JSON, mais, comme indiqué dans la question, vous pouvez choisir n'importe quel format lisible pour la sortie ou utiliser votre langue équivalente pour un dictionnaire. (Vous pouvez enregistrer 13 caractères en supprimant l' json_encodeinvocation).
Jacob
echone fonctionne pas avec les tableaux; mais le print_r($c);ferait, économisant 9 octets.
Titus
Mais ce n'est pas insensible à la casse. str_split(strtoupper($w))et ucfirst($w[0])peut résoudre cela (+21); ou $s=strtoupper($w);(+18)
Titus
1

PowerShell , 91 83 octets

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

Essayez-le en ligne!

Il lève une exception si un raccourci approprié est introuvable.

Déroulé:

$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
mazzy
la source
0

PHP, 153 octets

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

courir avec php-r '<code>' <<EOF+ Entrée + <word1>+ Entrée + <word2>+ Entrée + ... + EOF+ Entrée

travailler sur argv pour 155 octets :

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

courir avec php -r '<code>' <word1> <word2> ...

(-13 octets avec un global défini: foreach($i as$w)au lieu de foreach($argv as$i=>$w)if($i))

Titus
la source