I have a code like this:
def myfun(*args):
return {i: sum(k % i == 0 for k in args) for i in range(1,10)}
myfun(1,2,3,4,4,5,10,16,20)
{1: 9, 2: 6, 3: 1, 4: 4, 5: 3, 6: 0, 7: 0, 8: 1, 9: 0}
And I want to convert it to a function without a dict comprehension:
def myfun(*args):
for item in args:
for item_2 in range(1,10):
return {item_2:sum(item % item_2 == 0)}
myfun(1,2,3,4,4,5,10,16,20)
But I get:
----> 4 return {item_2:sum(item % item_2 == 0)}
5
6 myfun(1,2,3,4,4,5,10,16,20)
TypeError: 'bool' object is not iterable
What exactly is the bool value that is returned rather than the sum?
To unwrap the nested dict comprehension, you would end up with two for loops. First you'd iterate over your range and initialize a dict entry (your sum value) to 0. Then you'd loop over your args and do your mod check, and increment the value if necessary. This will emulate your sum expression.
def myfun(*args):
result = {}
for i in range(1,10):
result[i] = 0
for k in args:
if k % i == 0:
result[i] += 1
return result
>>> myfun(1,2,3,4,4,5,10,16,20)
{1: 9, 2: 6, 3: 1, 4: 4, 5: 3, 6: 0, 7: 0, 8: 1, 9: 0}
That's correct non dict comprehension syntax:
def myfun(*args):
result = {}
for i in range(1,10):
result[i] = sum(k % i == 0 for k in args)
return result
print(myfun(1,2,3,4,4,5,10,16,20))
Output:
{1: 9, 2: 6, 3: 1, 4: 4, 5: 3, 6: 0, 7: 0, 8: 1, 9: 0}
Related
This question already has answers here:
How do I count the occurrences of a list item?
(30 answers)
Closed 3 years ago.
I am trying to track seen elements, from a big array, using a dict.
Is there a way to force a dictionary object to be integer type and set to zero by default upon initialization?
I have done this with a very clunky codes and two loops.
Here is what I do now:
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = {}
for val in fl:
seenit[val] = 0
for val in fl:
seenit[val] = seenit[val] + 1
Of course, just use collections.defaultdict([default_factory[, ...]]):
from collections import defaultdict
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = defaultdict(int)
for val in fl:
seenit[val] += 1
print(fl)
# Output
defaultdict(<class 'int'>, {0: 1, 1: 3, 2: 1, 3: 1, 4: 1})
print(dict(seenit))
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
In addition, if you don't like to import collections you can use dict.get(key[, default])
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = {}
for val in fl:
seenit[val] = seenit.get(val, 0) + 1
print(seenit)
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
Also, if you only want to solve the problem and don't mind to use exactly dictionaries you may use collection.counter([iterable-or-mapping]):
from collections import Counter
fl = [0, 1, 1, 2, 1, 3, 4]
seenit = Counter(f)
print(seenit)
# Output
Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})
print(dict(seenit))
# Output
{0: 1, 1: 3, 2: 1, 3: 1, 4: 1}
Both collection.defaultdict and collection.Counter can be read as dictionary[key] and supports the usage of .keys(), .values(), .items(), etc. Basically they are a subclass of a common dictionary.
If you want to talk about performance I checked with timeit.timeit() the creation of the dictionary and the loop for a million of executions:
collection.defaultdic: 2.160868141 seconds
dict.get: 1.3540439499999999 seconds
collection.Counter: 4.700308418999999 seconds
collection.Counter may be easier, but much slower.
You can use collections.Counter:
from collections import Counter
Counter([0, 1, 1, 2, 1, 3, 4])
Output:
Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})
You can then address it like a dictionary:
>>> Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})[1]
3
>>> Counter({1: 3, 0: 1, 2: 1, 3: 1, 4: 1})[0]
1
Using val in seenit is a bit faster than .get():
seenit = dict()
for val in fl:
if val in seenit :
seenit[val] += 1
else:
seenit[val] = 1
For larger lists, Counter will eventually outperform all other approaches. and defaultdict is going to be faster than using .get() or val in seenit.
in python, if I want to find the max value of d, but the key only include 1,2,3 other than all the keys in the d. so how to do, thank you.
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
Just get the keys and values for the keys 1, 2 and 3 in a list of tuples, sort the list and get the first tuple element [0] key [0].
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
key_max_val = sorted([(k,v) for k,v in d.items() if k in [1,2,3]])[0][0]
print(key_max_val) # Outputs 1
You can use operator:
It will return you the key with maximum value:
In [873]: import operator
In [874]: d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
In [875]: max(d.iteritems(), key=operator.itemgetter(1))[0]
Out[875]: 1
I think this below should work (base on
#Mayank Porwal idea, sorry coz I can not reply):
d = {1: 5, 2: 0, 3: 4, 4: 0, 5: 1}
max(v for k,v in d.items())
Use a generator and the max builtin function:
Max value
max(v for k,v in d.items() if k in [1,2,3])
Max key
max(k for k,v in d.items() if k in [1,2,3])
I have nested list:
L = [[15,10], [11], [9,7,8]]
and need count groups like [15, 10] is 0 group, [11] is 1 group and [9,7,8] is 2 group - output is dictionary:
print (d)
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
I try:
d = {k:v for k,v in enumerate(L)}
d = {k: oldk for oldk, oldv in d.items() for k in oldv}
print (d)
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
I think my solution is a bit over-complicated. Is there some better, more pythonic solution?
What about using:
d = {v: i for i,l in enumerate(L) for v in l}
which generates:
>>> {v: i for i,l in enumerate(L) for v in l}
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
The idea is as follows: first we iterate over L with enumerate(L) and we thus obtain the index i of the sublist vs. Next we iterate over every element v in vs. For every v we associate v with i in the dictionary.
If there are collisions - a value that occurs twice in L - then the last index will be used.
You can use:
d = {v: i for i in range(len(L)) for v in L[i]}
output:
{7: 2, 8: 2, 9: 2, 10: 0, 11: 1, 15: 0}
iterating over L using range(len(L)) to access each list and assign each value as the key of the dictionary, and the index of the list as the value.
I have a dictionary like this:
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5: set([2]), 6: set([])}
and from this dictionary I want to build another dictionary that count the occurrences of keys in dict1 in every other value ,that is the results should be:
result_dict = {0: 1, 1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1}
My code was this :
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5:set([2]), 6: set([])}
result_dict = {}
for pair in dict1.keys():
temp_dict = list(dict1.keys())
del temp_dict[pair]
count = 0
for other_pairs in temp_dict :
if pair in dict1[other_pairs]:
count = count + 1
result_dict[pair] = count
The problem with this code is that it is very slow with large set of data.
Another attempt was in a single line, like this :
result_dict = dict((key ,dict1.values().count(key)) for key in dict1.keys())
but it gives me wrong results, since values of dict1 are sets:
{0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
thanks a lot in advance
I suppose, for a first stab, I would figure out which values are there:
all_values = set().union(*dict1.values())
Then I'd try to count how many times each value occurred:
result_dict = {}
for v in all_values:
result_dict[v] = sum(v in dict1[key] for key in dict1)
Another approach would be to use a collections.Counter:
result_dict = Counter(v for set_ in dict1.values() for v in set_)
This is probably "cleaner" than my first solution -- but it does involve a nested comprehension which can be a little difficult to grok. It does work however:
>>> from collections import Counter
>>> dict1
{0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5: set([2]), 6: set([])}
>>> result_dict = Counter(v for set_ in dict1.values() for v in set_)
Just create a second dictionary using the keys from dict1, with values initiated at 0. Then iterate through the values in the sets of dict1, incrementing values of result_dict as you go. The runtime is O(n), where n is the aggregate number of values in sets of dict1.
dict1 = {0: set([1, 4, 5]), 1: set([2, 6]), 2: set([3]), 3: set([0]), 4: set([1]), 5:set([2]), 6: set([])}
result_dict = dict.fromkeys(dict1.keys(), 0)
# {0: 0, 1: 0, 2: 0, 3: 0, 4: 0, 5: 0, 6: 0}
for i in dict1.keys():
for j in dict1[i]:
result_dict[j] += 1
print result_dict
# {0: 1, 1: 2, 2: 2, 3: 1, 4: 1, 5: 1, 6: 1}
I have 2 lists:
correct_list = [1,2,3,4,5,6,7,8,9,10]
other_list = [4,5,6,7,8,10]
I would like to combine these two lists so:
combined_list = [{k:1, v:0},{k:2, v:0},{k:3, v:0}, {k:4, v:4}, {etc}]
so basically am saying that the key is the correct list, and where ever the other_list does not match the correct_list, fill in a 0, or " " . And of they do match, fill in the matching value
Does this makes sense ?
How would I do this in python ?
[{'k': c, 'v': c if c in other_list else 0} for c in correct_list]
By the way, if the only elements of the dictionaries are k and v, consider building a dictionary instead of a list of dictionaries:
>>> dict((c, c if c in other_list else 0) for c in correct_list)
{1: 0, 2: 0, 3: 0, 4: 4, 5: 5, 6: 6, 7: 7, 8: 8, 9: 0, 10: 10}