Related
Let's say here is input:
input = {1:[2,3], 2:[], 3:[4,5,6], 4:[], 5:[], 6:[]}
This can be represented like below:
tree
If all leaf nodes are 1, we can change like this:
for idx, val in input[1]:
if len(input[val]) == 0:
input[1][idx] = [] # input[1] = [[], 3]
else:
input[1][idx] = input[val] # input[1] = [[], [4,5,6]]
And then somehow, input[1] can be input[1] = [[],[[],[],[]]].
So finally, i wanna get multiple numbers of each dict key elements compared to leaf nodes.
I am not sure the description that i wrote is clear.
Anyways, What i want to get is like:
# 2, 4, 5, 6 are all leaf nodes.
# 3 is including [4, 5, 6] which are all leaf nodes, then 3's value must be 3 (len[4,5,6])
# 1 is including [2, 3]. Among them, only 2 is leaf. And 3's value is 3. So output[1] = 1 + 3 = 4
output = {1:4, 2:1, 3:3, 4:1, 5:1, 6:1}
Simple recursion with functools.lru_cache:
from functools import lru_cache
def leaves_count(tree):
#lru_cache
def cntr(key):
value = tree[key]
return sum(map(cntr, value)) if value else 1
return {k: cntr(k) for k in tree}
Test:
>>> tree = {1: [2, 3], 2: [], 3: [4, 5, 6], 4: [], 5: [], 6: []}
>>> leaves_count(tree)
{1: 4, 2: 1, 3: 3, 4: 1, 5: 1, 6: 1}
Manually implement the cached version:
def leaves_count(tree):
def cntr(key):
cnt = cache.get(key)
if cnt:
return cnt
value = tree[key]
cache[key] = cnt = sum(map(cntr, value)) if value else 1
return cnt
cache = {}
return {k: cntr(k) for k in tree}
Using recursion method
Code:
dic= {1:[2,3], 2:[], 3:[4,5,6], 4:[], 5:[], 6:[]}
def recur(val, leaf):
for v in val:
if v in dic.keys():
if len(dic[v])==0:
leaf.append(v)
else:
recur(dic[v],leaf)
else:
leaf.append(v)
return len(leaf)
{key : 1 if recur(val,[])==0 else recur(val,[]) for key,val in dic.items()}
Output:
{1: 4, 2: 1, 3: 3, 4: 1, 5: 1, 6: 1}
Input: {1:[2,3], 2:[], 3:[4,5,6], 4:[], 5:[], 6:[7,8], 7:[], 8:[9,10], 9:[]}
Output: {1: 6, 2: 1, 3: 5, 4: 1, 5: 1, 6: 3, 7: 1, 8: 2, 9: 1}
I have a list as follows:
[[a,a,b,a,b,b,b],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
The number of lists containing numerical values is the same as the elements in the first list (that contains letters "a" or "b"). The length of the lists containing numbers is unknown a priori.
Each letter corresponds to a list in this way:
a --> 5,5,4,5
a --> 5,1,5
b --> 2,5
a --> 4,5
b --> 5
b --> 3
b --> 5
And then, count each value by letters "a" or "b", while keeping the values, for example "a" has in total 6 "5", 2 "4", and 1 "1". "b" has in total 3 "5", 1 "2", and 1 "3".
Expected result:
"a" has in total 6 "5", 2 "4", and 1 "1".
"b" has in total 3 "5", 1 "2", and 1 "3".
One approach:
from collections import Counter, defaultdict
lst = [["a", "a", "b", "a", "b", "b", "b"], [5, 5, 4, 5], [5, 1, 5], [2, 5], [4, 5], [5], [3], [5]]
result = defaultdict(Counter)
head, *tail = lst
for key, values in zip(head, tail):
result[key] += Counter(values)
for key, counts in result.items():
print(key, counts)
Output
a Counter({5: 6, 4: 2, 1: 1})
b Counter({5: 3, 2: 1, 3: 1})
An alternative:
head, *tail = lst
counts = Counter((key, value) for key, values in zip(head, tail) for value in values)
result = defaultdict(dict)
for (key, value), count in counts.items():
result[key][value] = count
for key, value in result.items():
print(key, value)
Output
a {5: 6, 4: 2, 1: 1}
b {2: 1, 5: 3, 3: 1}
This would be my approach:
inputs = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = {}
for k, v in zip(inputs[0], inputs[1:]):
if k in counts.keys():
counts[k] += v
else:
counts[k] = v
My output for this:
{'a': [5, 5, 4, 5, 5, 1, 5, 4, 5], 'b': [2, 5, 5, 3, 5]}
Then you can use Counters, len(), etc. to get the exact output formatting you want.
See below ( Counter and defaultdict are the main "players")
from collections import Counter,defaultdict
results = defaultdict(Counter)
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
for idx,x in enumerate(data[0],1):
results[x].update(data[idx])
for letter,counter in results.items():
print(f'{letter} -> {counter}')
output
a -> Counter({5: 6, 4: 2, 1: 1})
b -> Counter({5: 3, 2: 1, 3: 1})
It's a fun problem to solve.
from collections import Counter
data = [['a','a','b','a','b','b','b'],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
counts = { k:Counter() for k in list(set(data[0])) }
for i, k in enumerate(data[0], 1):
counts[k].update(data[i])
print(counts)
# {'a': Counter({5: 6, 4: 2, 1: 1}), 'b': Counter({5: 3, 2: 1, 3: 1})}
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {}
for i in l[0]:
if i not in d.keys():
d[i] = []
for i, item in zip(l[0],l[1:]):
d[i].append(item)
count_dict = {}
for i in d.keys():
count_dict[i] = {}
for j in d[i]:
elements = set(j)
for k in elements:
if str(k) not in count_dict[i].keys():
count_dict[i][str(k)] = j.count(k)
else:
count_dict[i][str(k)] += j.count(k)
for i,j in count_dict.items():
print('{} has {}'.format(i,j))
First off, you should really be doing your own homework
... I just love a good algo problem (adventOfCode, anyone?)
Steps:
don't forget " around strings in the list
create a dictionary to store counts within "a" and "b"
iterate over lists in indices 1-n
get the a/b bucket from: l[0][sublist_index - 1]
start a count for value, if not already counted: if v not in d[bucket].keys(): d[bucket][v] = 0
increment the counter for v, in the appropriate bucket: d[bucket][v] += 1
l = [["a","a","b","a","b","b","b"],[5,5,4,5],[5,1,5],[2,5],[4,5],[5],[3],[5]]
d = {"a": {}, "b": {}}
for sublist_index in range(1, len(l)):
bucket = l[0][sublist_index - 1]
for v in l[sublist_index]:
if v not in d[bucket].keys():
d[bucket][v] = 0
d[bucket][v] += 1
print(d)
and the output:
{'a': {5: 6, 4: 2, 1: 1}, 'b': {2: 1, 5: 3, 3: 1}}
I have a dictionary:
d = {1: 2,
2:3,
3: 4,
5:6,
6:7}
I want this output:
d= { 1: 4 , 2 :4 , 3:4 , 5:7 , 6:7}
basically 2 is parent of 1, 3 is parent of 2, 4 is parent of 3. I want to say that 1,2 and 3 is related to 4
For each key-value pair in the dict, you can use a while loop to keep checking if the current value is a valid key in the dict, and make the value of that key the new value, until the value is not a key, at which point you have found the leaf and you can assign that value to the current key:
for k, v in d.items():
while v in d:
v = d[v]
d[k] = v
so that given:
d = {1: 2,
2: 3,
3: 4,
5: 6,
6: 7}
d becomes:
{1: 4, 2: 4, 3: 4, 5: 7, 6: 7}
I know we use enumerate for iterating a list but I tried it on a dictionary and it didn't give an error.
CODE:
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, key in enumerate(enumm):
print(i, key)
OUTPUT:
0 0
1 1
2 2
3 4
4 5
5 6
6 7
Can someone please explain the output?
On top of the already provided answers there is a very nice pattern in Python that allows you to enumerate both keys and values of a dictionary.
The normal case you enumerate the keys of the dictionary:
example_dict = {1:'a', 2:'b', 3:'c', 4:'d'}
for i, k in enumerate(example_dict):
print(i, k)
Which outputs:
0 1
1 2
2 3
3 4
But if you want to enumerate through both keys and values this is the way:
for i, (k, v) in enumerate(example_dict.items()):
print(i, k, v)
Which outputs:
0 1 a
1 2 b
2 3 c
3 4 d
The first column of output is the index of each item in enumm and the second one is its keys. If you want to iterate your dictionary then use .items():
for k, v in enumm.items():
print(k, v)
And the output should look like:
0 1
1 2
2 3
4 4
5 5
6 6
7 7
Just thought I'd add, if you'd like to enumerate over the index, key, and values of a dictionary, your for loop should look like this:
for index, (key, value) in enumerate(your_dict.items()):
print(index, key, value)
dict1={'a':1, 'b':'banana'}
To list the dictionary in Python 2.x:
for k,v in dict1.iteritems():
print k,v
In Python 3.x use:
for k,v in dict1.items():
print(k,v)
# a 1
# b banana
Finally, as others have indicated, if you want a running index, you can have that too:
for i in enumerate(dict1.items()):
print(i)
# (0, ('a', 1))
# (1, ('b', 'banana'))
But this defeats the purpose of a dictionary (map, associative array) , which is an efficient data structure for telephone-book-style look-up. Dictionary ordering could be incidental to the implementation and should not be relied upon. If you need the order, use OrderedDict instead.
enumerate() when working on list actually gives the index and the value of the items inside the list.
For example:
l = [1, 2, 3, 4, 5, 6, 7, 8, 9]
for i, j in enumerate(list):
print(i, j)
gives
0 1
1 2
2 3
3 4
4 5
5 6
6 7
7 8
8 9
where the first column denotes the index of the item and 2nd column denotes the items itself.
In a dictionary
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, j in enumerate(enumm):
print(i, j)
it gives the output
0 0
1 1
2 2
3 4
4 5
5 6
6 7
where the first column gives the index of the key:value pairs and the second column denotes the keys of the dictionary enumm.
So if you want the first column to be the keys and second columns as values, better try out dict.iteritems()(Python 2) or dict.items() (Python 3)
for i, j in enumm.items():
print(i, j)
output
0 1
1 2
2 3
4 4
5 5
6 6
7 7
Voila
Since you are using enumerate hence your i is actually the index of the key rather than the key itself.
So, you are getting 3 in the first column of the row 3 4even though there is no key 3.
enumerate iterates through a data structure(be it list or a dictionary) while also providing the current iteration number.
Hence, the columns here are the iteration number followed by the key in dictionary enum
Others Solutions have already shown how to iterate over key and value pair so I won't repeat the same in mine.
Iterating over a Python dict means to iterate over its keys exactly the same way as with dict.keys()
The order of the keys is determined by the implementation code and you cannot expect some specific order:
Keys and values are iterated over in an arbitrary order which is
non-random, varies across Python implementations, and depends on the
dictionary’s history of insertions and deletions. If keys, values and
items views are iterated over with no intervening modifications to the
dictionary, the order of items will directly correspond.
That's why you see the indices 0 to 7 in the first column. They are produced by enumerate and are always in the correct order. Further you see the dict's keys 0 to 7 in the second column. They are not sorted.
That sure must seem confusing. So this is what is going on. The first value of enumerate (in this case i) returns the next index value starting at 0 so 0, 1, 2, 3, ... It will always return these numbers regardless of what is in the dictionary. The second value of enumerate (in this case j) is returning the values in your dictionary/enumm (we call it a dictionary in Python). What you really want to do is what roadrunner66 responded with.
Python3:
One solution:
enumm = {0: 1, 1: 2, 2: 3, 4: 4, 5: 5, 6: 6, 7: 7}
for i, k in enumerate(enumm):
print("{}) d.key={}, d.value={}".format(i, k, enumm[k]))
Output:
0) enumm.key=0, enumm.value=1
1) enumm.key=1, enumm.value=2
2) enumm.key=2, enumm.value=3
3) enumm.key=4, enumm.value=4
4) enumm.key=5, enumm.value=5
5) enumm.key=6, enumm.value=6
6) enumm.key=7, enumm.value=7
An another example:
d = {1 : {'a': 1, 'b' : 2, 'c' : 3},
2 : {'a': 10, 'b' : 20, 'c' : 30}
}
for i, k in enumerate(d):
print("{}) key={}, value={}".format(i, k, d[k])
Output:
0) key=1, value={'a': 1, 'b': 2, 'c': 3}
1) key=2, value={'a': 10, 'b': 20, 'c': 30}
You may find it useful to include index inside key:
d = {'a': 1, 'b': 2}
d = {(i, k): v for i, (k, v) in enumerate(d.items())}
Output:
{(0, 'a'): True, (1, 'b'): False}
d = {0: 'zero', '0': 'ZERO', 1: 'one', '1': 'ONE'}
print("List of enumerated d= ", list(enumerate(d.items())))
output:
List of enumerated d= [(0, (0, 'zero')), (1, ('0', 'ZERO')), (2, (1, 'one')), (3, ('1', 'ONE'))]
I have the following multi-dictionary which get output from a file and in my script, its taken as standard input:
{ 345 : {'name': 5, 'count': 6, 'top': 0} }
{ 233 : {'name': 6, 'count': 4, 'top': 0} }
{ 123 : {'name': 2, 'count': 9, 'top': 1} }
I want to convert all the keys of the dictionary to numbers like this:
{ 1 : {'1': 5, '2': 6, '3': 0} }
{ 2 : {'1': 6, '2': 4, '3': 0} }
{ 3 : {'1': 2, '2': 9, '3': 1} }
Output of the file should be:
1 1: 5 2: 6 3: 0
2 1: 6 2: 4 3: 0
3 1: 2 2: 9 3: 1
I am trying to understand dictionaries and new to python so wondering how I can achieve it.
Here is my code
for line in sys.stdin:
d = ast.literal_eval(line)
for k,v in d.items():
inner_dict = dicts.setdefault(k, {})
inner_dict= dict((t,i) for (t,i) in enumerate(sorted(dicts.keys())))
for key, value in inner_dict.items():
print key, value
The above code gives me the following output but does not give me what I want.
0 123
1 233
2 345
Where am I going wrong.
Produce dictionaries as specified in the example:
# generate individual converted dictionaries
# not tested with sys.stdin
def gen_with_appropriate_name():
for n, line in enumerate(sys.stdin, 1):
d = ast.literal_eval(line)
sub_d = d.values()[0]
yield {n : {'1' : sub_d['name'],
'2' : sub_d['count'],
'3' : sub_d['top']}}
The following will produce a similar result with the enumeration of the sub dictionary based on its original keys, sorted.
# generate individual converted dictionaries
# not tested with sys.stdin
def gen_with_appropriate_name():
for n, line in enumerate(sys.stdin, 1):
d = ast.literal_eval(line)
items = d.values()[0].items()
items.sort(key = lambda itm: itm[0])
yield {n: {i+1:item[1] for i, item in enumerate(items)}}
Usage -with printout in format specified
d = gen_with_appropriate_name()
for thing in d:
first = str(thing.keys()[0])
second = thing.values()[0]
print first + ' ' + ' '.join('{}: {}'.format(*item) for item in second.iteritems())
Output using the first function:
1 1: 5 3: 0 2: 6
2 1: 6 3: 0 2: 4
3 1: 2 3: 1 2: 9
Output using second function
1 1: 6 2: 5 3: 0
2 1: 4 2: 6 3: 0
3 1: 9 2: 2 3: 1
Explanation:
gen_with appropriate_name()
This function gets data from sys.stdin one line at a time and generates a dictionary for each of those lines in turn. It is iterable. http://docs.python.org/2.7/glossary.html#term-iterable
yield {n: {i+1:item[1] for i, item in enumerate(items)}}
The yield statement makes the function a generator. The function is suspended at the yield statement until next() is called, then execution resumes til another yield statement is encountered. A generator's next() method returns the value of the yield statement's expression list.
http://docs.python.org/2.7/reference/expressions.html#yieldexpr
{n: {i+1:item[1] for i, item in enumerate(items)}}
This is the yield statement's expression list. It creates a dictionary with n as the key. The value is a dictionary created with a dictionary display which is similar to a list comprehension.
http://docs.python.org/2.7/reference/expressions.html#displays-for-sets-and-dictionaries