Take the 2-minute tour ×
Programming Puzzles & Code Golf Stack Exchange is a question and answer site for programming puzzle enthusiasts and code golfers. It's 100% free, no registration required.

In the fewest bytes, generate the dictionary of keypresses for any letter (as described in https://code.google.com/codejam/contest/351101/dashboard#s=p2)

In Python, the dictionary literal itself:

{'a':2,'c':222,'b':22,'e':33,'d':3,'g':4,'f':333,'i':444,'h':44,'k':55,'j':5,'m':6,'l':555,'o':666,'n':66,'q':77,'p':7,'s':7777,'r':777,'u':88,'t':8,'w':9,'v':888,'y':999,'x':99,'z':9999}

is 187 bytes so it needs to be less than that. (The values can be strings or ints, ie you can have 'a':'2' or 'a':2 it's up to you)

NOTE: This is not asking you to solve the referenced GCJ problem, it's just asking you to generate a particular dictionary which is related to that problem.

EDIT: You may solve this in any language which has a dictionary-like type (ie hashmap, associative array etc.)

share|improve this question
    
Do we have to solve this in Python, or can we use any language to generate and output the dictionary literal? –  Ilmari Karonen Apr 11 at 19:48
    
I guess any language. Let me fix that –  dspyz Apr 11 at 19:49
1  
Also, looks like the GCJ problem itself has been asked here before. –  Ilmari Karonen Apr 11 at 19:51
    
Huh, I should have checked that first. I posted this because we were talking about how to generate this dictionary (in Python) on #gcj on Freenode –  dspyz Apr 11 at 19:53
    
Order doesn't matter? –  kukac67 Apr 11 at 20:22

10 Answers 10

up vote 6 down vote accepted

perl, 49 48 bytes

Using a different algorithm than my previous answer, we can lose another 12 bytes. The basic idea is that you usually just add the digit from the last letter's solution over again. We handle the other cases (detected by a short regex) by starting with a single instance of the last digit + 1.

{map{$d++,$t=""if/[dgjmptw]/;$_,$t.=$d||=2}a..z}

With output:

ski@anito:~/src$ perl -MData::Dumper  -e '$Data::Dumper::Sortkeys=1; $d=2;print Dumper {map{$d++,$t=""if/[dgjmptw]/;$_,$t.=$d}a..z}'
$VAR1 = {
      'a' => '2',
      'b' => '22',
      'c' => '222',
      'd' => '3',
      'e' => '33',
      'f' => '333',
      'g' => '4',
      'h' => '44',
      'i' => '444',
      'j' => '5',
      'k' => '55',
      'l' => '555',
      'm' => '6',
      'n' => '66',
      'o' => '666',
      'p' => '7',
      'q' => '77',
      'r' => '777',
      's' => '7777',
      't' => '8',
      'u' => '88',
      'v' => '888',
      'w' => '9',
      'x' => '99',
      'y' => '999',
      'z' => '9999'
};
share|improve this answer
    
Woo! Suck it J and Golfscript. Perl 4 eva! ;-) –  skibrianski Jun 1 at 17:17

Golfscript, 68 characters

"{'"26,{.[.",'"''if\97+"':"]''+\..11-
7/.0>*-.3/2[+]\3%)@18=+*}/"9}"

What's this, you say? It outputs the correct Python dict literal:

{'a':2,'b':22,'c':222,'d':3,'e':33,'f':333,'g':4,'h':44,'i':444,'j':5,'k':55,'l':555,'m':6,'n':66,'o':666,'p':7,'q':77,'r':777,'s':7777,'t':8,'u':88,'v':888,'w':9,'x':99,'y':999,'z':9999}

That is,

$ echo print `ruby golfscript.rb phonetyp.gs` | python
{'a': 2, 'c': 222, 'b': 22, 'e': 33, 'd': 3, 'g': 4, 'f': 333, 'i': 444, 'h': 44, 'k': 55, 'j': 5, 'm': 6, 'l': 555, 'o': 666, 'n': 66, 'q': 77, 'p': 7, 's': 7777, 'r': 777, 'u': 88, 't': 8, 'w': 9, 'v': 888, 'y': 999, 'x': 99, 'z': 9999}
share|improve this answer

Python (83)(87)

c,d=97,{}
for i in range(2,10):
 for j in range(1,4+(i>6)*i%2):d[chr(c)],c=j*str(i),c+1

The dictionary is stored in d. The condition check (i>6)*i%2 saves two chars from (i in[7,9]).

Edit:

c=97;d={}
for i in range(8):
 for j in range(1,4+(i|2>6)):d[chr(c)]=j*str(i+2);c+=1

Shaved 4 characters. With i shifted down by 2, we recognize the special cases of 7 and 9 by checking if i is 5 or 7 using i|2>6.

share|improve this answer
    
(6<i<10) saves another character. –  isaacg Apr 11 at 22:34
1  
@isaacg but it includes 8... –  YatharthROCK Apr 12 at 12:18

Python, 86 characters

Alternate Python solution:

d={}
for a in range(26):n=a-max(0,(a-11)/7);d[chr(a+97)]=`n/3+2`*(n%3+1+(a in(18,25)))
share|improve this answer
    
For this range max(0,(a-11)/7) = max(0,a-11)/7 = a/18-a/25. You can squeeze 2 or even 6 more bytes ;) –  core1024 May 19 at 14:09

J - 57 char

The closest analogue to the dictionary datatype in J is a table of boxes: each row is an entry, containing the key on the left and the data on the right. It's not really unordered, but whenever you need a dictionary type of record, you would use something like this.

_2]\;n(;&.><\)/@|:/.n,.~u:97+i.#n=.,":"0(#~3+e.&7 9)2+i.8

n is the string '22233344455566677778889999', which we create by taking the list 2 3 4 5 6 7 8 9 and taking three of 4 of each element, depending on whether the element is 7 or 9. Then we just convert each item to a string and run them together into a single string.

Then we make the alphabet, attach the digits to the alphabet with ,.~, and then group them by the digits (this is /. at work). Within each group, we pair off the letter with the corresponding prefix of the string of same digits.

Finally, we run things together: ; to take off the effects of the earlier grouping and _2]\ to put it into the proper table shape.

   _2]\;n(;&.><\)/@|:/.n,.~u:97+i.#n=.,":"0(#~3+e.&7 9)2+i.8
+-+----+
|a|2   |
+-+----+
|b|22  |
+-+----+
|c|222 |
+-+----+
|d|3   |
+-+----+
|e|33  |
+-+----+
|f|333 |
+-+----+
|g|4   |
+-+----+
|h|44  |
+-+----+
|i|444 |
+-+----+
|j|5   |
+-+----+
|k|55  |
+-+----+
|l|555 |
+-+----+
|m|6   |
+-+----+
|n|66  |
+-+----+
|o|666 |
+-+----+
|p|7   |
+-+----+
|q|77  |
+-+----+
|r|777 |
+-+----+
|s|7777|
+-+----+
|t|8   |
+-+----+
|u|88  |
+-+----+
|v|888 |
+-+----+
|w|9   |
+-+----+
|x|99  |
+-+----+
|y|999 |
+-+----+
|z|9999|
+-+----+
share|improve this answer

perl, 61 bytes

Examine the mod3 and div3 of a counter $t to determine the base digit and number of repetitions. Handle the special cases of s and z separately.

$t=5;{map{$b=++$t%3+1;$b=4,--$t if/s|z/;$_,int($t/3)x$b}a..z}

With string output:

perl -MData::Dumper -e '$Data::Dumper::Sortkeys=1; $t=5;print Dumper {map{$b=++$t%3+1;$b=4,--$t if/s|z/;$_,int($t/3)x$b}a..z}' 
$VAR1 = {
      'a' => '2',
      'b' => '22',
      'c' => '222',
      'd' => '3',
      'e' => '33',
      'f' => '333',
      'g' => '4',
      'h' => '44',
      'i' => '444',
      'j' => '5',
      'k' => '55',
      'l' => '555',
      'm' => '6',
      'n' => '66',
      'o' => '666',
      'p' => '7',
      'q' => '77',
      'r' => '777',
      's' => '7777',
      't' => '8',
      'u' => '88',
      'v' => '888',
      'w' => '9',
      'x' => '99',
      'y' => '999',
      'z' => '9999'
    };

And here's a more readable version of the code:

{
  map {
    my $reps = (++$pos % 3) + 1;
    if($_ =~ /s|z/) {
      --$pos;
      $reps=4;
    }
    my $digit = int( $pos/3 );
    $_ => $digit x $reps
  } ('a'..'z')
}

We start with $pos = 5 so that int(++$pos/3) starts off at 2.

We handle the case of s and z separately since they are the only exceptions to the modulo 3 rule.

share|improve this answer

JavaScript (ES5) 88 86 85 bytes

for(o={},a=c=2,b=96;a-10;a=a<(c%9%7?b:1e3)?a+[c]:++c)o[String.fromCharCode(++b)]=+a;o

Result:

{"a":2,"b":22,"c":222,"d":3,"e":33,"f":333,"g":4,"h":44,"i":444,"j":5,"k":55,"l":555,"m":6,"n":66,"o":666,"p":7,"q":77,"r":777,"s":7777,"t":8,"u":88,"v":888,"w":9,"x":99,"y":999,"z":9999}

If mixed types are allowed, it can be reduced by 1 byte.

86 84 bytes:

for(o={},a=c=2,b=96;a-10;a=a<(c%9%7?b:1e3)?a+[c]:++c)o[String.fromCharCode(++b)]=a;o

Result:

{"a":2,"b":"22","c":"222","d":3,"e":"33","f":"333","g":4,"h":"44","i":"444","j":5,"k":"55","l":"555","m":6,"n":"66","o":"666","p":7,"q":"77","r":"777","s":"7777","t":8,"u":"88","v":"888","w":9,"x":"99","y":"999","z":"9999"}
share|improve this answer

Mathematica, 168

This is the longest answer here... I'm sure there's a better way to do this.

(k=#2[[1]]+1;Append[{},{#->StringJoin@ConstantArray[ToString@k,#2]}]&~MapIndexed~#)&~MapIndexed~Characters@{"abc","def","ghi","jkl","mno","pqrs","tuv","wxyz"}~Flatten~3

Output:

{"a" -> "2", "b" -> "22", "c" -> "222", "d" -> "3", "e" -> "33", 
"f" -> "333", "g" -> "4", "h" -> "44", "i" -> "444", "j" -> "5", 
"k" -> "55", "l" -> "555", "m" -> "6", "n" -> "66", "o" -> "666", 
"p" -> "7", "q" -> "77", "r" -> "777", "s" -> "7777", "t" -> "8", 
"u" -> "88", "v" -> "888", "w" -> "9", "x" -> "99", "y" -> "999", 
"z" -> "9999"}
share|improve this answer

Bash + coreutils, 91 bytes

p="printf %s\n"
paste <($p {a..z}) <($p {2..9} {22..99..11} {222..999..111} 7777 9999|sort)

Generates a tab-delimited table, which is a natural structure for a shell script - not sure if that meets the specs or not:

a   2
b   22
c   222
d   3
...
r   777
s   7777
t   8
u   88
v   888
w   9
x   99
y   999
z   9999

Pure Bash, 137 bytes

Not very good.

declare -A a
b=({X..z})
for n in {9..33};do
c=${b[n]}
((n>26?n--:n))
printf -vk %$[n%3+1]s
a[$c]=${k// /$[n/3-1]}
done
a[s]+=7
a[z]=9999

This populates a bash associative array.

Crudely display it as follows:

$ for c in ${!a[@]}; do echo -n $c:${a[$c]},;done; echo
a:2,b:22,c:222,d:3,e:33,f:333,g:4,h:44,i:444,j:5,k:55,l:555,m:6,n:66,o:666,p:7,q:77,r:777,s:7777,t:8,u:88,v:888,w:9,x:99,y:999,z:9999,
$ 
share|improve this answer

Python 2 (97)

I used a single dictionary comprehension:

{zip(*[(chr(i)for i in range(65,91))]*3)[i][k]:str(i+2)*(k+1)for k in range(3)for i in range(8)}

Unfortunately it's missing the z because on number 9 there are 4 letters.

share|improve this answer
    
You could manually add the z for a few more characters. Also remove the space between the many ...) for... to ...)for... –  user80551 Apr 12 at 10:20
    
Y is also missing –  user80551 Apr 12 at 10:21

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.