メニューのキーボードショートカットを生成する


10

メニューのショートカット

従来、ユーザーメニューには、などのキーボードショートカットを使用してアクセスしAlt + (a letter)たり、すべてのテキストボックスがフォーカスされていない場合(Gmailスタイル)に文字を入力するだけでアクセスしたりできます。

あなたのタスク

入力としてメニューエントリが与えられた場合、タスクは各メニューエントリに適切なショートカット文字を付与することです。

一連の単語-メニューエントリ(文字列の配列または同等の言語として)を受け入れ、辞書またはハッシュマップを1文字からメニューエントリに返す関数またはプログラムを記述します。

パラメータを使用して値を返すか、STDINを使用して結果をSTDOUTに出力できます。グローバル/スコープ変数がすでに入力されていると想定することはできません

適切な文字を決定するアルゴリズム

  • 基本的にそれは単語の最初の利用可能な文字です。以下の仮定と例を参照してください。
  • すべてのエントリの文字が利用できない場合、ショートカットはになります(a letter) + (a number)。エントリからどの文字を選ぶかは任意です。番号は0から始まり、1ずつ増加する必要があります-すべてのショートカットが一意になるようにします。以下の3番目の例を参照してください。

仮定

  • 入力はセットになります。つまり、繰り返しはなく、すべてのエントリは一意です。
  • 入力の長さは、負でない整数(言語のMAX_INTまで)にすることができます。
  • 大文字と小文字の区別:入力では大文字と小文字が区別されます(ただし、大文字と小文字を区別しない場合は一意のままです)。結果には、元のエントリと元の大文字小文字が含まれているはずです。ただし、出力ショートカット文字は大文字と小文字を区別しません。
  • すべての入力単語が数字で終わるわけではありません。
  • 「邪悪な入力」はテストされません。「邪悪な入力」とは、特定の文字のカウンターを10回以上インクリメントする必要があるようなものです。

以下の例はJSONですが、配列と辞書に相当する言語を使用できます。または、STD I / Oを使用している場合は、入力と出力に読み取り可能な形式(csv、さらにはスペースなど)を使用できます。区切り値)。

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

勝利条件

最短のコードが勝ちます。ASCIIのみが許可されます。


「a」はすでに最初のエントリで使用されています。したがって、「aa」の場合、その両方の文字がすでに使用されているため、a0を取得します。b0-b2と同じです。
素晴らしい14年

数字がなくなるとどうなりますか?
nderscore 2014年

@nderscoreそれは本当に必要ですか?
seequ

['ab', 'a']与えるべき{a:'ab', a0:'a'}{b:'ab', a:'a'}
アダム

@Adámはどちらも受け入れ可能です。入力配列を順番にスキャンするので、前者を実装する方が簡単ですが、何らかの理由で後者を好む場合は、それを実行してください。
ジェイコブ

回答:


4

ジャバスクリプト(ES6106 105 100

この関数は、入力を配列として取り、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

結果:

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

非ゴルフ/コメント:

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
}

美しいです。悪質な入力['a', 'aa', 'aaa', 'aaaa', 'aaaaa', 'aaaaaa', 'aaaaaaa', 'aaaaaaaa', 'aaaaaaaaa', 'aaaaaaaaaa', 'aaaaaaaaaaa', 'aaaaaaaaaaaa']では失敗するかもしれませんが、そのようなエッジケースは無視できると思いませんか?
ジェイコブ

@Jacobそして、ヒットすると11どうなりますか?キーボードショートカットで1つのキーを2回押すことはできません:P
nderscore

あなたはそこにポイントを持っています(キーストロークの終わり(200ms程度)まで待つ実装を考えると可能かもしれませんが)。とにかく、そのような邪悪な入力はテストされないという仮定に加えます。
Jacob

2

Python 2.x- 176170157114バイト

非常にシンプルなアプローチですが、誰かがゲームをキックする必要があります。

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)

例:

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

必要な説明はゴルフされていないコードだけだと思います。(これは実際には元のバージョンです)

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

@Jacobに感謝します。入力フォーマットは素晴らしいです。
seequ

2

JavaScript(ECMAScript 6)-107文字

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)

説明:

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

テスト:

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

1

PHP> = 5.4-149文字

PHPの標準(ここにスニッガーを挿入)によると、入力はの'代わりに使用するため有効なJSONではない"ため、少し生意気で、実際の変数宣言として入力を使用しています。

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

例を使用して:

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

ゴルファーされていないそれはかなり基本的です:

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

PHPにはジャンプ宣言がありますか?そうだ... 90年代。
seequ

2
JSONにこだわる必要はありません。私はJSONの例のみを提供しましたが、質問で述べたように、出力には読み取り可能な形式を選択するか、辞書と同等の言語を使用できます。(json_encode呼び出しを削除すると、13文字を節約できます)。
Jacob

echo配列では機能しません。しかし、print_r($c);9バイトを保存し、それを行うだろう。
タイタス

しかし、これは大文字小文字を区別しません。str_split(strtoupper($w))そしてそれucfirst($w[0])を解決することができます(+21); または$s=strtoupper($w);(+18)
タイタス

1

PowerShell91 83バイト

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

オンラインでお試しください!

適切なショートカットが見つからない場合は、例外がスローされます。

展開:

$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

0

PHP、153バイト

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

で実行php-r '<code>' <<EOF+ + Enterキー<word1>+ Enterキー+ <word2>+入力+ ... + EOF入力+

155バイトの argvの作業:

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

と一緒に走る php -r '<code>' <word1> <word2> ...

(定義されたグローバルで-13バイト:のforeach($i as$w)代わりにforeach($argv as$i=>$w)if($i)

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.