Generate keyboard shortcuts for a menu
Javascript (ES6) 106 105 100
This function takes input as an an array and outputs a javascript object.
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
Results:
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 / Commented:
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
}
Python 2.x - 176 170 157 114 bytes
Very simple approach, but someone has to kick the game going.
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)
Examples:
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'}
I think the only required explanation is the ungolfed code. (This actually is the original version)
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
JavaScript (ECMAScript 6) - 107 Characters
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)
Explanation:
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"}