from itertools import product
a = [1, 2, 3]
dict1 = {"x": 1, "y": 2, "z": 3}
dict2 = {"r": 4, "s": 5, "t": 6}
for i in product(a, dict1, dict2):
print(i)
and I got:
(1, 'x', 'r')
(1, 'x', 's')
(1, 'x', 't')
(1, 'y', 'r')
(1, 'y', 's')
(1, 'y', 't')
(1, 'z', 'r')
(1, 'z', 's')
(1, 'z', 't')
(2, 'x', 'r')
(2, 'x', 's')
(2, 'x', 't')
(2, 'y', 'r')
(2, 'y', 's')
(2, 'y', 't')
(2, 'z', 'r')
(2, 'z', 's')
(2, 'z', 't')
(3, 'x', 'r')
(3, 'x', 's')
(3, 'x', 't')
(3, 'y', 'r')
(3, 'y', 's')
(3, 'y', 't')
(3, 'z', 'r')
(3, 'z', 's')
(3, 'z', 't')
But I want to get these instead:
(1, {"x": 1, "y": 2, "z": 3}, {"r": 4, "s": 5, "t": 6})
(2, {"x": 1, "y": 2, "z": 3}, {"r": 4, "s": 5, "t": 6})
(3, {"x": 1, "y": 2, "z": 3}, {"r": 4, "s": 5, "t": 6})
How can I do this? Maybe I should use another function instead of product in this case? Please kindly help. Thanks!
Your requested output looks like you printed some tuples:
a = [1, 2, 3]
dict1 = {"x": 1, "y": 2, "z": 3}
dict2 = {"r": 4, "s": 5, "t": 6}
for n in a:
print( (n, dict1, dict2) )
The issues is, that itertools.product will return all product for each element of the iterables provided, so you could get a similar result to your expected result by wraping the two dicts into another iterable:
for i in list(product(a, [(dict1, dict2)])):
print(i)
(1, ({'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}))
(2, ({'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}))
(3, ({'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}))
The ouput is similar to what you asked for, but the dictionaries are wrappen inside a tupel.
This resembles what you ask for:
a = [1, 2, 3]
dict1 = {"x": 1, "y": 2, "z": 3}
dict2 = {"r": 4, "s": 5, "t": 6}
[[e, dict1, dict2] for e in a]
[[1, {'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}],
[2, {'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}],
[3, {'x': 1, 'y': 2, 'z': 3}, {'r': 4, 's': 5, 't': 6}]]
The key thing to note is that you really only want to iterate over a, since dict1 and dict2 are just content you are copying wholesale.
Related
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}
I need to fill an array with elements which are dictionaries. For example:
a = np.empty(2,2)
and I need to fill it in this way (which is not allowed)
for i in range(2):
for j in range(2):
a[i,j] = {'x': b[i], 'y': c[j]}
where band c are other lists/arrays or columns of a dataframe.
import numpy as np
a = np.zeros((2, 2))
b = np.ones(a.shape[0])
c = np.ones(a.shape[1]) * [2]
list_a = a.tolist()
for i in range(2):
for j in range(2):
list_a[i][j] = {'x': b[i], 'y': c[j]}
a = np.array(list_a)
print(a)
Output:
array([[{'x': 1.0, 'y': 2.0}, {'x': 1.0, 'y': 2.0}],
[{'x': 1.0, 'y': 2.0}, {'x': 1.0, 'y': 2.0}]], dtype=object)
If you create an object dtype array, you can put anything in the slots:
In [9]: a = np.empty((2,2), object)
In [10]: a
Out[10]:
array([[None, None], # empty() fills with None
[None, None]], dtype=object)
In [11]: for i in range(2):
...: for j in range(2):
...: a[i,j] = {'x':b[i], 'y':c[j]}
...:
In [12]: a
Out[12]:
array([[{'x': 1, 'y': 4}, {'x': 1, 'y': 3}],
[{'x': 3, 'y': 4}, {'x': 3, 'y': 3}]], dtype=object)
But a list comprehension works just as well
In [13]: [[{'x':b[i],'y':c[j]} for j in range(2)] for i in range(2)]
Out[13]: [[{'x': 1, 'y': 4}, {'x': 1, 'y': 3}], [{'x': 3, 'y': 4}, {'x': 3, 'y': 3}]]
In [14]: np.array(_)
Out[14]:
array([[{'x': 1, 'y': 4}, {'x': 1, 'y': 3}],
[{'x': 3, 'y': 4}, {'x': 3, 'y': 3}]], dtype=object)
Or you could start with a flat list, and reshape the array:
In [15]: [{'x':b[i],'y':c[j]} for j in range(2) for i in range(2)]
Out[15]: [{'x': 1, 'y': 4}, {'x': 3, 'y': 4}, {'x': 1, 'y': 3}, {'x': 3, 'y': 3}]
In [16]: np.array(_)
Out[16]:
array([{'x': 1, 'y': 4}, {'x': 3, 'y': 4}, {'x': 1, 'y': 3},
{'x': 3, 'y': 3}], dtype=object)
In [18]: _.reshape(2,2)
Out[18]:
array([[{'x': 1, 'y': 4}, {'x': 3, 'y': 4}],
[{'x': 1, 'y': 3}, {'x': 3, 'y': 3}]], dtype=object)
This array of dictionaries won't be any easier or faster to use than the list(s).
Alternatively we could create a structured array with 2 named fields. Start with a list of tuples:
In [19]: [(b[i],c[j]) for j in range(2) for i in range(2)]
Out[19]: [(1, 4), (3, 4), (1, 3), (3, 3)]
In [20]: np.array(_, dtype=[('x',int),('y',int)])
Out[20]: array([(1, 4), (3, 4), (1, 3), (3, 3)], dtype=[('x', '<i8'), ('y', '<i8')])
In [21]: _.reshape(2,2)
Out[21]:
array([[(1, 4), (3, 4)],
[(1, 3), (3, 3)]], dtype=[('x', '<i8'), ('y', '<i8')])
In [22]: _['x']
Out[22]:
array([[1, 3],
[1, 3]])
In contrast to get all the x values from the 2d object array:
In [24]: [i['x'] for i in a.flat]
Out[24]: [1, 1, 3, 3]
how to recursively sort all nested iterable in an iterable?
e.g.
d = {
'e': [{'y': 'y'}, {'x': [{'2': 2, '1': 1}]}],
'x': ['c', 'b', 'a'],
'z': {
'a': [3, 1, 2],
'd': [{'y': [6,5,1]}, {'w': 1}],
'c': {'2': 2, '3': 3, '4': 4}
},
'w': {1:1, 2:2, 3:3}
}
I was the output like
{'e': [{'x': [{'1': 1, '2': 2}]}, {'y': 'y'}],
'w': {1: 1, 2: 2, 3: 3},
'x': ['a', 'b', 'c'],
'z': {'a': [1, 2, 3],
'c': {'2': 2, '3': 3, '4': 4},
'd': [{'w': 1}, {'y': [1, 5, 6]}]}}
from pprint import pprint
d = {
'e': [{'y': 'y'}, {'x': [{'2': 2, '1': 1}]}],
'x': ['c', 'b', 'a'],
'z': {
'a': [3, 1, 2],
'd': [{'y': [6,5,1]}, {'w': 1}],
'c': {'2': 2, '3': 3, '4': 4}
},
'w': {1:1, 2:2, 3:3}
}
def rec_sort(iterable):
"""Recursively sort
"""
def sort_dict_key(x):
if isinstance(x, dict):
return sorted(x.keys(), key=sort_dict_key)
return x
if isinstance(iterable, dict):
d = {}
for k, v in iterable.items():
d[k] = rec_sort(v)
elif isinstance(iterable, list):
iterable.sort(key=sort_dict_key)
for pos,item in enumerate(iterable):
iterable[pos] = rec_sort(item)
return iterable
pprint(rec_sort(d))
You can use recursion:
import json
d = {'x': ['c', 'b', 'a'], 'z': {'a': [3, 1, 2], 'c': {'3': 3, '2': 2, '4': 4}, 'd': [{'y': [6, 5, 1]}, {'w': 1}]}, 'e': [{'y': 'y'}, {'x': [{'1': 1, '2': 2}]}], 'w': {1: 1, 2: 2, 3: 3}}
def sort_nested(c):
if not isinstance(c, dict):
return sorted(c) if isinstance(c, list) else c
return {a:sorted(sort_nested(i) for i in b) if isinstance(b, list) else sort_nested(b) for a, b in c.items()}
print(json.dumps(sort_nested(d), indent=4))
Output:
{
"x": [
"a",
"b",
"c"
],
"z": {
"a": [
1,
2,
3
],
"c": {
"3": 3,
"2": 2,
"4": 4
},
"d": [
{
"w": 1
},
{
"y": [
1,
5,
6
]
}
]
},
"e": [
{
"x": [
{
"1": 1,
"2": 2
}
]
},
{
"y": "y"
}
],
"w": {
"1": 1,
"2": 2,
"3": 3
}
}
I am trying to use python to help me crack Vigenère ciphers. I am fairly new to programming but I've managed to make an algorithm to analyse single letter frequencies. This is what I have so far:
Ciphertext = str(input("What is the cipher text?"))
Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
def LetterFrequency():
LetterFrequency = {'A': 0, 'B': 0, 'C': 0, 'D': 0, 'E': 0, 'F': 0, 'G': 0, 'H': 0, 'I': 0, 'J': 0, 'K': 0, 'L': 0, 'M': 0, 'N': 0, 'O': 0, 'P': 0, 'Q': 0, 'R': 0, 'S': 0, 'T': 0, 'U': 0, 'V': 0, 'W': 0, 'X': 0, 'Y': 0, 'Z': 0}
for letter in Ciphertext.upper():
if letter in Letters:
LetterFrequency[letter]+=1
return LetterFrequency
print (LetterFrequency())
But is there a way for me to print the answers in descending order starting from the most frequent letter? The answers are shown in random order right now no matter what I do.
Also does anyone know how to extract specific letters form a large block of text to perform frequency analysis? So for instance if I wanted to put every third letter from the text “THISISARATHERBORINGEXAMPLE” together to analyse, I would need to get:
T H I
S I S
A R A
T H E
R B O
R I N
G E X
A M P
L E
Normally I would have to do this by hand in either notepad or excel which takes ages. Is there a way to get around this in python?
Thanks in advance,
Tony
For the descending order you could use Counter:
>>> x = "this is a rather boring example"
>>> from collections import Counter
>>> Counter(x)
Counter({' ': 5, 'a': 3, 'e': 3, 'i': 3, 'r': 3, 'h': 2, 's': 2, 't': 2, 'b': 1, 'g': 1, 'm': 1, 'l': 1, 'o': 1, 'n': 1, 'p': 1, 'x': 1})
As for the second question you could iterate per 3.
To exclude spaces you can try what #not_a_robot suggests in the comment or
delete it manually like:
>>> y = Counter(x)
>>> del y[' ']
>>> y
Counter({'a': 3, 'e': 3, 'i': 3, 'r': 3, 'h': 2, 's': 2, 't': 2, 'b': 1, 'g': 1, 'm': 1, 'l': 1, 'o': 1, 'n': 1, 'p': 1, 'x': 1})
Another approach, although the collections.Counter example from #coder is your best bet.
from collections import defaultdict
from operator import itemgetter
Letters = "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
Ciphertext = "this is a rather boring example"
def LetterFrequency():
LetterFrequency = {letter: 0 for letter in Letters}
for letter in Ciphertext.upper():
if letter in Letters:
LetterFrequency[letter]+=1
return LetterFrequency
def sort_dict(dct):
return sorted(dct.items(), key = itemgetter(1), reverse = True)
print(sort_dict(LetterFrequency()))
Which prints this, a list of tuples sorted descendingly by frequency:
[('A', 3), ('I', 3), ('E', 3), ('R', 3), ('T', 2), ('S', 2), ('H', 2), ('L', 1), ('G', 1), ('M', 1), ('P', 1), ('B', 1), ('N', 1), ('O', 1), ('X', 1), ('Y', 0), ('J', 0), ('D', 0), ('U', 0), ('F', 0), ('C', 0), ('Q', 0), ('W', 0), ('Z', 0), ('K', 0), ('V', 0)]
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})