Generate the python dictionary of phone keypresses for any letter

6

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

dspyz

Posted 2014-04-11T19:35:06.263

Reputation: 875

Do we have to solve this in Python, or can we use any language to generate and output the dictionary literal? – Ilmari Karonen – 2014-04-11T19:48:58.290

I guess any language. Let me fix that – dspyz – 2014-04-11T19:49:30.837

1

Also, looks like the GCJ problem itself has been asked here before.

– Ilmari Karonen – 2014-04-11T19:51:24.650

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 – 2014-04-11T19:53:25.210

Order doesn't matter? – kukac67 – 2014-04-11T20:22:24.393

You should be using an unordered data-type. This problem isn't to "output" the result, it's to "generate" it – dspyz – 2014-04-11T20:26:34.517

Do all values have to be the same type? ex:{a:2,b:"22"...} and do the dictionary keys have to be lowercase letters? – nderscore – 2014-04-11T21:04:29.037

Is the idea to store it in a variable or to print a correctly-formatted dict literal? The latter seems more interesting – Claudiu – 2014-04-11T22:49:54.057

Answers

6

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

skibrianski

Posted 2014-04-11T19:35:06.263

Reputation: 1 197

Woo! Suck it J and Golfscript. Perl 4 eva! ;-) – skibrianski – 2014-06-01T17:17:44.180

3

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.

xnor

Posted 2014-04-11T19:35:06.263

Reputation: 115 687

(6<i<10) saves another character. – isaacg – 2014-04-11T22:34:42.550

1@isaacg but it includes 8... – Yatharth Agarwal – 2014-04-12T12:18:21.343

3

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}

Claudiu

Posted 2014-04-11T19:35:06.263

Reputation: 3 870

2

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

Claudiu

Posted 2014-04-11T19:35:06.263

Reputation: 3 870

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 – 2014-05-19T14:09:22.737

1

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

nderscore

Posted 2014-04-11T19:35:06.263

Reputation: 4 912

1

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.

skibrianski

Posted 2014-04-11T19:35:06.263

Reputation: 1 197

1

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|
+-+----+

algorithmshark

Posted 2014-04-11T19:35:06.263

Reputation: 8 144

1

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

kukac67

Posted 2014-04-11T19:35:06.263

Reputation: 2 159

0

Clojure, 91 bytes

(zipmap(map char(range 97 123))(for[i(range 2 10)r(range 1(get{7 5 9 5}i 4))](repeat r i)))

for is ideal for generating these kinds of sequences. Output looks like this:

{\a (2), \b (2 2), \c (2 2 2), \d (3), ...

NikoNyrh

Posted 2014-04-11T19:35:06.263

Reputation: 2 361

0

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,
$ 

Digital Trauma

Posted 2014-04-11T19:35:06.263

Reputation: 64 644

0

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.

Rnhmjoj

Posted 2014-04-11T19:35:06.263

Reputation: 101

You could manually add the z for a few more characters. Also remove the space between the many ...) for... to ...)for... – user80551 – 2014-04-12T10:20:06.583

Y is also missing – user80551 – 2014-04-12T10:21:57.890