Creating a Python dictionary using a comprehension - python

I am trying to create a python dictionary with the following values in python 2.7.3:
'A':1
'B':2
'C':3
.
.
.
.
'Z':26
using either of the following lines:
theDict = {x:y for x in map(chr,range(65,91)) for y in range(1,27)}
or
theDict = {x:y for x in map(chr,range(65,91)) for y in list(range(1,27))}
In both cases, I get the following result:
'A':26
'B':26
'C':26
.
.
.
.
'Z':26
I don't understand why the second for is not generating the numbers 1-26. Maybe it is, but if so, I don't understand why I am only getting 26 for the value of each key. If I don't create a dictionary (i.e. change x:y with just x or y), x = capital letters and y = 1-26.
Can someone explain what I am doing wrong and suggest a possible approach to get the result that I want.

Why it's wrong: Your list comprehension is nested. It's effectively something like this:
d = {}
for x in map(chr, range(65, 91)):
for y in range(1,27):
d[x] = y
As you can see, this isn't what you want. What it does is set y to 1, then walk through the alphabet, setting all letters to 1 i.e. {'A':1, 'B':1, 'C':1, ...}. Then it does it again for 2,3,4, all the way to 26. Since it's a dict, later settings overwrite earlier settings, and you see your result.
There are several options here, but in general, the solution to iterate over multiple companion lists is a pattern more like this:
[some_expr(a,b,c) for a,b,c in zip((a,list,of,values), (b, list, of, values), (c, list, of values))]
The zip pulls one value from each of the sublists and makes it into a tuple for each iteration. In other words, it converts 3 lists of 4 items each, into 4 lists of 3 items each (in the above). In your example, you have 2 lists of 26 items, when you want 26 pairs; zip will do that for you.

Try:
>>> {chr(k):k-64 for k in range(65,91)}
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4, 'G': 7, 'F': 6, 'I': 9, 'H': 8, 'K': 11, 'J': 10, 'M': 13, 'L': 12, 'O': 15, 'N': 14, 'Q': 17, 'P': 16, 'S': 19, 'R': 18, 'U': 21, 'T': 20, 'W': 23, 'V': 22, 'Y': 25, 'X': 24, 'Z': 26}
Or, if you want to do what you are doing use zip:
>>> {x:y for x,y in zip(map(chr,range(65,91)),range(1,27))}
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4, 'G': 7, 'F': 6, 'I': 9, 'H': 8, 'K': 11, 'J': 10, 'M': 13, 'L': 12, 'O': 15, 'N': 14, 'Q': 17, 'P': 16, 'S': 19, 'R': 18, 'U': 21, 'T': 20, 'W': 23, 'V': 22, 'Y': 25, 'X': 24, 'Z': 26}
The reason yours is not working, is that your comprehension is executing the inner the outer loop times. ie, try this in the shell:
>>> [(chr(outter), inner) for outter in range(65,91) for inner in range(1,27)]
[('A', 1), ('A', 2), ('A', 3), ('A', 4),... ('A', 26),
...
...
('Z', 1), ('Z', 2), ('Z', 3), ('Z', 4), ..., ('Z', 26)]
So if you do:
>>> len([(chr(outter), inner) for outter in range(65,91) for inner in range(1,27)])
676
You can see that it is executing 26x26 times (26x26=676)
Since a dict will just update with the new value, the last value for each letter is used:
>>> dict([(chr(outter), inner) for outter in range(65,91) for inner in range(1,27)])
{'A': 26, 'C': 26, 'B': 26, 'E': 26, 'D': 26, 'G': 26, 'F': 26, 'I': 26, 'H': 26, 'K': 26, 'J': 26, 'M': 26, 'L': 26, 'O': 26, 'N': 26, 'Q': 26, 'P': 26, 'S': 26, 'R': 26, 'U': 26, 'T': 26, 'W': 26, 'V': 26, 'Y': 26, 'X': 26, 'Z': 26}
Which shows why you are getting what you are getting.

You can try the following:
theDict = {chr(y):y - 64 for y in range(65, 91)}
print theDict
Output:
{'A': 1, 'C': 3, 'B': 2, 'E': 5, 'D': 4, 'G': 7, 'F': 6, 'I': 9, 'H': 8, 'K': 11, 'J': 10, 'M': 13, 'L': 12, 'O': 15, 'N': 14, 'Q': 17, 'P': 16, 'S': 19, 'R': 18, 'U': 21, 'T': 20, 'W': 23, 'V': 22, 'Y': 25, 'X': 24, 'Z': 26}

Related

Map Lowercase Alphabet to Integers [duplicate]

This question already has answers here:
creating dict where keys are alphabet letters and values are 1-26 using dict comprehension
(9 answers)
Closed 2 months ago.
i cant make a dict where to every one letter will be a value in the n + 1 format, start from 1.
this is my code:
dict1 = {x: y for x in 'abcdefghijklmnopqrstunvwxyz' for y in range(1, 20, 1)}
print(dict1)
i get it:
{'a': 19, 'b': 19, 'c': 19, 'd': 19, 'e': 19, 'f': 19, 'g': 19, 'h': 19, 'i': 19, 'j': 19, 'k': 19, 'l': 19, 'm': 19, 'n': 19, 'o': 19, 'p': 19, 'q': 19, 'r': 19, 's': 19, 't': 19, 'u': 19, 'v': 19, 'w': 19, 'y': 19, 'z': 19}
can u tell me why and how to get it: {'a': 1, 'b':2...
Use the tools provided by Python to make this easier to implement and read. First, don't hardcode the lowercase alphabet, use the stdlib string. Next, don't do the arithmetic yourself, it's easy to get wrong: there are 26 letters but range(1, 20, 1) generates only 19 digits. You also have a typo in your alphabet (I assume): tunvw. Lastly, use enumerate() which generates tuples consisting of an element of a sequence and an auto-incrementing integer, and use the start keyword argument to set the starting integer value.
import string
d = {x: y for x, y in enumerate(string.ascii_lowercase, start=1)}
Your code doesn't produce the result you want because for each integer from 1 to 19, it assigns the integer to the value for each key ('a', 'b', 'c', etc.). The first iteration of the outer for produces the dictionary {'a': 1, 'b': 2, 'c': 3, etc.}. Then, each subsequent iteration of the outer for overwrites these values with the new integer: 2, 3, 4, etc.
This is easy to see if we convert the comprehension to loops:
d = {}
for y in range(1, 20, 1):
for x in 'abcdefghijklmnopqrstuvwxyz':
d[x] = y
print(d)
{'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'f': 1, 'g': 1, 'h': 1, 'i': 1, 'j': 1, 'k': 1, 'l': 1, 'm': 1, 'n': 1, 'o': 1, 'p': 1, 'q': 1, 'r': 1, 's': 1, 't': 1, 'u': 1, 'v': 1, 'w': 1, 'x': 1, 'y': 1, 'z': 1}
{'a': 2, 'b': 2, 'c': 2, 'd': 2, 'e': 2, 'f': 2, 'g': 2, 'h': 2, 'i': 2, 'j': 2, 'k': 2, 'l': 2, 'm': 2, 'n': 2, 'o': 2, 'p': 2, 'q': 2, 'r': 2, 's': 2, 't': 2, 'u': 2, 'v': 2, 'w': 2, 'x': 2, 'y': 2, 'z': 2}
{'a': 3, 'b': 3, 'c': 3, 'd': 3, 'e': 3, 'f': 3, 'g': 3, 'h': 3, 'i': 3, 'j': 3, 'k': 3, 'l': 3, 'm': 3, 'n': 3, 'o': 3, 'p': 3, 'q': 3, 'r': 3, 's': 3, 't': 3, 'u': 3, 'v': 3, 'w': 3, 'x': 3, 'y': 3, 'z': 3}
...
{'a': 19, 'b': 19, 'c': 19, 'd': 19, 'e': 19, 'f': 19, 'g': 19, 'h': 19, 'i': 19, 'j': 19, 'k': 19, 'l': 19, 'm': 19, 'n': 19, 'o': 19, 'p': 19, 'q': 19, 'r': 19, 's': 19, 't': 19, 'u': 19, 'v': 19, 'w': 19, 'x': 19, 'y': 19, 'z': 19}
edit: You don't need a comprehension to do this. There is another, pretty clean solution:
import string
d = dict(enumerate(string.ascii_lowercase, start=1))
This solution relies on the dict(iterable) constructor:
Help on class dict in module builtins:
class dict(object)
| dict() -> new empty dictionary
| dict(mapping) -> new dictionary initialized from a mapping object's
| (key, value) pairs
| dict(iterable) -> new dictionary initialized as if via:
| d = {}
| for k, v in iterable:
| d[k] = v
Try to zip the alphabet and the range to see what you get like that:
z1 = zip('abcdefghijklmnopqrstunvwxyz', range(1, 28, 1))
Which will give us:
for tup in z1:
print(tup)
Output:
('a', 1)
('b', 2)
('c', 3)
('d', 4)
('e', 5)
('f', 6)
('g', 7)
('h', 8)
('i', 9)
('j', 10)
('k', 11)
('l', 12)
('m', 13)
('n', 14)
('o', 15)
('p', 16)
('q', 17)
('r', 18)
('s', 19)
('t', 20)
('u', 21)
('n', 22)
('v', 23)
('w', 24)
('x', 25)
('y', 26)
('z', 27)
Now you can assign each element of each tuple to x, y:
d1 = {x, y for x, y in zip('abcdefghijklmnopqrstunvwxyz', range(1, 28, 1))}
Output:
print(d1)
{'a': 1,
'b': 2,
'c': 3,
'd': 4,
'e': 5,
'f': 6,
'g': 7,
'h': 8,
'i': 9,
'j': 10,
'k': 11,
'l': 12,
'm': 13,
'n': 22,
'o': 15,
'p': 16,
'q': 17,
'r': 18,
's': 19,
't': 20,
'u': 21,
'v': 23,
'w': 24,
'x': 25,
'y': 26,
'z': 27}

Converting a list of dictionaries to a list by using certain keys

I have list of dictionaries which the dictionary size (number of keys) is not constant. Here is an example:
data = [{'t': 1633098324445950024,
'y': 1633098324445929497,
'q': 1636226,
'i': '57337',
'x': 12,
's': 15,
'c': [14, 37, 41],
'p': 139.55,
'z': 3},
{'t': 1633098324445958000,
'y': 1633098324445929497,
'q': 1636229,
'i': '57340',
'x': 12,
's': 100,
'c': [14, 41],
'p': 139.55,
'z': 3},
{'t': 1633098324445958498,
'y': 1633098324445594112,
'q': 1636230,
'i': '31895',
'x': 11,
's': 60,
'c': [14, 37, 41],
'p': 139.55,
'z': 3},
{'t': 1633098324446013523,
'y': 1633098324445649152,
'q': 1636231,
'i': '31896',
'x': 11,
's': 52,
'c': [14, 37, 41],
'p': 139.55,
'z': 3},
{'t': 1633098324472392943,
'y': 1633098324472133407,
'q': 1636256,
'i': '3417',
'x': 15,
's': 100,
'p': 139.555,
'z': 3},
{'t': 1633098324478972256,
'y': 1633098324478000000,
'f': 1633098324478949693,
'q': 1636260,
'i': '58051',
'x': 4,
'r': 12,
's': 100,
'p': 139.555,
'z': 3}]
As it is in the sample each dictionary has different length and they do not necessarily have the same keys. I need to extract certain elements based on the key. I am using [(d['t'],d['p'],d['s']) for d in data] and the results looks like this:
[(1633098324445950024, 139.55, 15),
(1633098324445958000, 139.55, 100),
(1633098324445958498, 139.55, 60),
(1633098324446013523, 139.55, 52),
(1633098324472392943, 139.555, 100),
(1633098324478972256, 139.555, 100)]
But I need to have values with 'c' key and when I run the following I got KeyError:
[(d['t'],d['p'],d['s'],d['c']) for d in data]
Traceback (most recent call last):
File "<ipython-input-108-8533763f150e>", line 1, in <module>
[(d['t'],d['p'],d['s'],d['c']) for d in data]
File "<ipython-input-108-8533763f150e>", line 1, in <listcomp>
[(d['t'],d['p'],d['s'],d['c']) for d in data]
KeyError: 'c'
One approach:
res = [(d['t'], d['p'], d['s']) + ((d['c'],) if 'c' in d else tuple()) for d in data]
pprint.pprint(res)
Output
[(1633098324445950024, 139.55, 15, [14, 37, 41]),
(1633098324445958000, 139.55, 100, [14, 41]),
(1633098324445958498, 139.55, 60, [14, 37, 41]),
(1633098324446013523, 139.55, 52, [14, 37, 41]),
(1633098324472392943, 139.555, 100),
(1633098324478972256, 139.555, 100)]
Why don't you try this:
value_list = [(d.get('t', ''), d.get('p', ''), d.get('s', ''), d.get('c', [])) for d in data]
print(value_list)
Output:
[(1633098324445950024, 139.55, 15, [14, 37, 41]),
(1633098324445958000, 139.55, 100, [14, 41]),
(1633098324445958498, 139.55, 60, [14, 37, 41]),
(1633098324446013523, 139.55, 52, [14, 37, 41]),
(1633098324472392943, 139.555, 100, []),
(1633098324478972256, 139.555, 100, [])]
def convert_to_list(list_of_dicts, keys):
"""
Convert a list of dictionaries to a list by using certain keys.
:param list_of_dicts: list of dictionaries
:param keys: list of keys
:return: list
"""
return [{key: dic[key] for key in keys} for dic in list_of_dicts]
if __name__ == '__main__':
list_of_dicts = [{'name': 'John', 'age': 21}, {'name': 'Mark', 'age': 25}]
keys = ['name', 'age']
print(convert_to_list(list_of_dicts, keys))

Sort value in dictionary by value in Python

I have something like this in Python to count the frequency of characters in a text, but i can't sort the values on the dictionary "v".
abcedario='abcdefghijklmnopqrstvuxwyz'
v = {}
count = 0
for c in abcedario:
count = 0
for char in text:
if c == char:
count = count +1
v[c] = count
sorted(v.items(), key=lambda x:x[1])
print v
I try to search here on stackoverflow but never solve my problem, the aspect of the output is this:
{'a': 2, 'b': 4, 'e': 4, 'd': 36, 'g': 31, 'f': 37, 'i': 14, 'h': 4, 'k': 51, 'j': 31, 'l': 34, 'n': 18, 'q': 13, 'p': 2, 'r': 9, 'u': 1, 't': 1, 'w': 36, 'v': 15, 'y': 14, 'x': 8, 'z': 10}
I want sort by value, so it's different from other posts.
If you just want to print them in order, just print the output of sorted:
abcedario='abcdefghijklmnopqrstvuxwyz'
v = {}
count = 0
for c in abcedario:
count = 0
for char in text:
if c == char:
count = count +1
v[c] = count
print sorted(v.items(), key=lambda x:x[1])
For text = "helloworld" you get:
[('e', 1), ('d', 1), ('h', 1), ('r', 1), ('w', 1), ('o', 2), ('l', 3)]
A python dictionary is an unordered collection of items. Therefore, it can't be sorted.
Try looking into OrderedDict from collections.
you can use Counter
from collections import Counter
text = "I have something like this in Python to count the frequency of characters in a text, but i can't sort the values on the dictionary"
print(Counter(text))
output:
Counter({' ': 24, 't': 15, 'e': 11, 'n': 9, 'h': 8, 'i': 8, 'o': 8, 'a': 7, 'c': 6, 's': 5, 'r': 5, 'u': 4, 'y': 3, 'f': 2, 'l': 2, 'v': 2, "'": 1, 'q': 1, 'd': 1, 'I': 1, 'm': 1, 'g': 1, 'b': 1, 'x': 1, ',': 1, 'P': 1, 'k': 1})

Create python dictionary by enumerate function

I am looking for a simpler way to create this python dictionary. May I know if enumerate function can help?
a_dict = {'a':0, 'b':1, 'c':2, ....}
Using enumerate you can use a generator expression and string.ascii_lowercasewithin within dict :
>>> import string
>>> dict((j,i) for i,j in enumerate(string.ascii_lowercase))
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8, 'h': 7, 'k': 10, 'j': 9, 'm': 12, 'l': 11, 'o': 14, 'n': 13, 'q': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20, 't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}
As enumerate returns tuples in format (index,element) you can loop over it and just change the indices with element then convert it to dict.
I would use an infinite number generator like itertools.count to generate numbers from 0. Then zip the ascii characters with count and create the tuples needed for the dictionary generation.
>>> from itertools import count, izip
>>> import string
>>>
>>> dict(izip(string.ascii_lowercase, count()))
{'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8, 'h': 7, 'k': 10, 'j': 9, 'm': 12, 'l': 11, 'o': 14, 'n': 13, 'q': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20, 't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}
you may simply use string.ascii_lowercase which is string of all lowercase characters, then you zip the lowercase letters and list of number ranging from 0 to len(string.ascii_lowercase) and then convert them to dict.
However you may want to use some other set of alphabet as string.ascii_letters, string.ascii_uppercase , string.letters, string.punctuation, etc.
You can easily filter the keys that you want in your dictionary either by concatenating the above mentioned strings as string.ascii_lowercase+string.ascii_uppercase would give us a string containing first the 26 lowercase alphabets and then 26 uppercase alphabets, you may also apply slicing methods to get desired set of characters, like string.ascii_lowercase[0:15] would give you "abcdefghijklmn"
import string
alphabets = string.ascii_lowercase
print dict(zip(alphabets, range(len(alphabets))))
>>> {'a': 0, 'c': 2, 'b': 1, 'e': 4, 'd': 3, 'g': 6, 'f': 5, 'i': 8, 'h': 7, 'k': 10, 'j': 9, 'm': 12, 'l': 11, 'o': 14, 'n': 13, 'q': 16, 'p': 15, 's': 18, 'r': 17, 'u': 20, 't': 19, 'w': 22, 'v': 21, 'y': 24, 'x': 23, 'z': 25}
Assuming the .... means you want the alphabet:
{chr(i+97): i for i in range(26)}

What is the most elegant way to initialize a dictionary consists of chars and digits

I'm looking of creating a dictionary in python
which its keys are the chars '0' to '9' , afterwards keys from 'a' to 'z',
and their ids should be a counter from 0 to 36
like this:
dict = {'0':0, '1':1, '2':2, ....., '9':9, 'a':10, .... , 'x':33, 'y':34, 'z':35}
I manage to write this
dict = {}
for i in range(10):
dict[str(i)] = i
ord_a = ord('a')
for i in range(0,26):
dict[chr(ord_a + i)] = i+10
Can you help me with a better way to implement it?
And one more thing, print(dict) returns an unsorted object:
{'d': 13, 'e': 14, 'f': 15, 'g': 16, 'r': 27, 'a': 10, 'b': 11,
'c': 12, 'l': 21, 'm': 22, 'n': 23, 'o': 24, 'h': 17, 'i': 18,
'j': 19, 'k': 20, '4': 4, '5': 5, '6': 6, '7': 7, '0': 0, '1': 1,
'2': 2, '3': 3, '8': 8, '9': 9, 'z': 35, 't': 29, 'u': 30,
'x': 33, 'v': 31, 'y': 34, 'w': 32, 's': 28, 'p': 25, 'q': 26}
Why's that? I actually initialize it quite sorted, no?
import string
keys = string.digits+string.ascii_lowercase
values = range(len(keys))
d = dict(zip(keys,values))
dicts have unordered keys. To have ordered keys, use a collections.OrderedDict. (Also, never name a variable dict or list, etc., since this prevents you from easily accessing the Python built-in of the same name. The built-in is useful, as you can see above.)

Categories

Resources