Generieren Sie Tastaturkürzel für ein Menü

10

Menüverknüpfungen

Auf Benutzermenüs kann traditionell über Tastaturkürzel zugegriffen werden, z. B. durch Alt + (a letter)einfaches Drücken des Buchstabens, wenn alle Textfelder nicht fokussiert sind ( Google Mail- Stil).

Deine Aufgabe

Angesichts der Menüeinträge als Eingabe besteht Ihre Aufgabe darin, jedem Menüeintrag einen richtigen Verknüpfungsbuchstaben zuzuweisen.

Schreiben Sie eine Funktion oder ein Programm, das eine Reihe von Wörtern akzeptiert - die Menüeinträge (als Array von Zeichenfolgen oder Ihr Sprachäquivalent) und ein Wörterbuch oder eine Hashmap von einem einzelnen Buchstaben zu einem Menüeintrag zurückgibt.

Sie können entweder einen Parameter verwenden und einen Wert zurückgeben oder STDIN verwenden und Ihre Ergebnisse an STDOUT ausgeben. Sie dürfen nicht davon ausgehen, dass eine globale Variable / scope bereits mit der Eingabe gefüllt ist.

Algorithmus zur Bestimmung des richtigen Buchstabens

  • Grundsätzlich ist es der erste verfügbare Buchstabe des Wortes. Siehe Annahmen und Beispiele unten.
  • Falls nicht alle Buchstaben des Eintrags verfügbar sind, wird die Verknüpfung angezeigt (a letter) + (a number). Welcher Buchstabe Sie aus dem Eintrag auswählen, ist beliebig. Die Zahl sollte bei 0 beginnen und um 1 erhöht werden - damit alle Verknüpfungen eindeutig sind. Siehe drittes Beispiel unten.

Annahmen

  • Die Eingabe ist ein Set, dh keine Wiederholungen, jeder Eintrag ist eindeutig.
  • Die Länge der Eingabe kann eine beliebige nicht negative Ganzzahl sein (bis zu MAX_INT Ihrer Sprache).
  • Groß- und Kleinschreibung beachten: Die Eingabe unterscheidet zwischen Groß- und Kleinschreibung (bleibt jedoch eindeutig, wenn Groß- und Kleinschreibung ignoriert wird). Die Ergebnisse sollten die Originaleinträge mit ihrem Originalgehäuse enthalten. Bei den Ausgabe-Verknüpfungsbuchstaben wird jedoch nicht zwischen Groß- und Kleinschreibung unterschieden.
  • Alle eingegebenen Wörter enden nicht mit Zahlen.
  • Es wird kein "böser Input" getestet. "Böse Eingabe" ist so, dass Sie den Zähler eines bestimmten Buchstabens mehr als 10 Mal erhöhen müssen.

Beispiele

Die folgenden Beispiele sind in JSON enthalten. Sie können jedoch Ihr Sprachäquivalent für ein Array und ein Wörterbuch verwenden oder - falls Sie STD I / O verwenden - ein beliebiges lesbares Format für Ihre Eingabe und Ausgabe (z. B. CSV oder sogar Leerzeichen). getrennte Werte).

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

Gewinnbedingungen

Der kürzeste Code gewinnt. Nur ASCII ist erlaubt.

Jakob
quelle
"a" wird bereits vom ersten Eintrag übernommen. Für "aa" erhält es also a0, da beide Buchstaben bereits belegt sind. Gleiches gilt für b0-b2.
Mattacular
Was passiert, wenn Ihnen die Zahlen ausgehen?
Nderscore
@nderscore Ist das wirklich notwendig?
siehe
Sollte ['ab', 'a']geben {a:'ab', a0:'a'}oder {b:'ab', a:'a'}?
Adám
@ Adám beide sind akzeptabel. Ersteres wäre einfacher zu implementieren, da Sie das Eingabearray in geordneter Weise scannen. Wenn Sie jedoch aus irgendeinem Grund Letzteres bevorzugen, entscheiden Sie sich dafür.
Jacob

Antworten:

4

Javascript ( ES6 ) 106 105 100

Diese Funktion nimmt die Eingabe als Array und gibt ein Javascript-Objekt aus.

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

Ergebnisse:

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

Ungolfed / Kommentiert:

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
quelle
Das ist schön. Es mag für den bösen Input scheitern ['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaaa', 'aaaaaaaaaaaa'], aber ich denke, wir können solche Randfälle ignorieren, nicht wahr?
Jacob
@ Jacob Und was passiert, wenn wir treffen 11? Sie können die eine Taste in einer Tastenkombination nicht zweimal drücken: P
nderscore
Sie haben dort einen Punkt (obwohl dies bei einer Implementierung möglich sein könnte, die bis zum Ende der Tastenanschläge wartet (ca. 200 ms)). Wie auch immer, ich werde zu den Annahmen hinzufügen, dass kein derart böser Input getestet wird.
Jacob
2

Python 2.x - 176 170 157 114 Bytes

Sehr einfacher Ansatz, aber jemand muss das Spiel in Gang bringen.

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)

Beispiele:

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

Ich denke, die einzige erforderliche Erklärung ist der ungolfed Code. (Dies ist eigentlich die Originalversion)

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
quelle
Ich muss mich bescheiden bei @Jacob bedanken. Das Eingabeformat ist einfach toll.
siehe
2

JavaScript (ECMAScript 6) - 107 Zeichen

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)

Erläuterung:

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
quelle
1

PHP> = 5,4 - 149 Zeichen

Gemäß den PHP-Standards (hier Snigger einfügen) ist die Eingabe nicht gültig, da JSON 'anstelle von verwendet wird. Daher war" ich etwas frech und verwende die Eingabe als tatsächliche Variablendeklaration:

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

Anhand der Beispiele:

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

Ohne Golf ist es ziemlich einfach:

<?
$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
quelle
PHP hat Sprungdeklarationen? Das ist so ... 90er.
siehe
2
Sie müssen sich nicht an JSON halten, ich habe nur die Beispiele in JSON bereitgestellt, aber wie in der Frage angegeben, können Sie ein beliebiges lesbares Format für die Ausgabe auswählen oder Ihr Sprachäquivalent für ein Wörterbuch verwenden. (Sie können 13 Zeichen speichern, indem Sie den json_encodeAufruf entfernen .)
Jacob
echofunktioniert nicht mit Arrays; print_r($c);würde es aber tun und 9 Bytes sparen.
Titus
Dies ist jedoch nicht unempfindlich. str_split(strtoupper($w))und ucfirst($w[0])kann das lösen (+21); oder $s=strtoupper($w);(+18)
Titus
1

PowerShell , 91 83 Byte

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

Probieren Sie es online aus!

Es wird eine Ausnahme ausgelöst, wenn keine richtige Verknüpfung gefunden wurde.

Abgerollt:

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

Laufen Sie mit php-r '<code>' <<EOF+ Enter + <word1>+ Enter + <word2>+ Enter + ... + EOF+ Enter

Arbeiten an argv für 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);

laufen mit php -r '<code>' <word1> <word2> ...

(-13 Bytes mit einem definierten globalen: foreach($i as$w)anstelle von foreach($argv as$i=>$w)if($i))

Titus
quelle