I have the following list:
lst= (1,(1,2), 3, (3,4), 1, 3)
and I want to use the dictionary function generate output that will count the number of times each value occurs such that it would look like this:
{1:3, 2:1, 3:3, 4:1}
I am lost on how to do this.
Thank you!
Below is my attempt:
def f(*args):
for x in args:
d = {x:args.count(x) for x in args}
return d
For arbitrary depth tuples, you could use a recursive function for flattening:
def flatten_nested_tuples(tuples):
for tup in tuples:
if isinstance(tup, tuple):
yield from flatten_nested_tuples(tup)
else:
yield tup
The yield from x syntax is equivalent to the for item in x: yield item. Its just a shorter way to create generators. You can have a look at this answer and this answer for more information about generators and the yield keyword.
To count we can use collections.Counter to count the flattened tuples:
from collections import Counter
lst= (1,(1,2), 3, (3,4), 1, 3)
print(Counter(flatten_nested_tuples(lst)))
Output:
Counter({1: 3, 3: 3, 2: 1, 4: 1})
Note: Counter is a subclass of dict, so you can treat it like a regular dict.
If you want to count yourself without any modules, you have to do the 0 initializing yourself:
counts = {}
for item in flatten_nested_tuples(lst):
counts[item] = counts.get(item, 0) + 1
print(counts)
# {1: 3, 2: 1, 3: 3, 4: 1}
Or without using dict.get():
counts = {}
for item in flatten_nested_tuples(lst):
if item not in counts:
counts[item] = 0
counts[item] += 1
print(counts)
# {1: 3, 2: 1, 3: 3, 4: 1}
Related
I tried to add the string elements to the dictionary but it doesnt work
adatok = ["marha", 1, "kacsa", 2, "kacsa", 1, "birka", 3, "marha", 4, "marha", 2]
sorszámok = list(set([x for x in adatok if type(x) == int]))
szótár = {}
for i in sorszámok:#Létrehozzuk a sorszámokat egy szótárba
szótár.update({i:set()})
for j in adatok:
if type(j) == int:
szótár[j].add(adatok[adatok.index(j)-1])
#Expected output:{1: {'marha','kacsa'}, 2: {'kacsa','marha'}, 3: {'birka'}, 4: {'marha'}}
#Output:{1: {'marha'}, 2: {'kacsa'}, 3: {'birka'}, 4: {'marha'}}
Instead of starting with unique keys and then trying to find the values for each key, iterate over the key, value pairs and add them to the sets. Using defaultdict saves you the trouble of setting up the dict ahead of time.
>>> from collections import defaultdict
>>> adatok = ["marha", 1, "kacsa", 2, "kacsa", 1, "birka", 3, "marha", 4, "marha", 2]
>>> szótár = defaultdict(set)
>>> for k, v in zip(adatok[1::2], adatok[0::2]):
... szótár[k].add(v)
...
>>> dict(szótár)
{1: {'marha', 'kacsa'}, 2: {'marha', 'kacsa'}, 3: {'birka'}, 4: {'marha'}}
counts = defaultdict(int)
for elem in sets: #list of sets
for _ in elem: #each set contains elements that may be duplicates among the sets
counts[_] += 1
Is there a way to use dict comprehension for code like this?
Don't use a list comprehension for side effects (i.e. updating counts).
Instead, if you replace defaultdict(int) with Counter, you can write the solution in one line. (I assume your end goal is to make your code shorter/cleaner.)
sets = [
{1, 2, 3},
{1, 2},
{3},
{3}]
# ---
from collections import Counter
counts = Counter(x for s in sets for x in s)
print(counts) # -> Counter({3: 3, 1: 2, 2: 2})
Note: Instead of the nested generator expression, you might prefer to use itertools.chain.from_iterable(sets).
If you are adamant at using list comprehension, you can do this way:
>>> counts = {1:4, 2:5, 3:8, 4:2, 5:9}
>>> sets = [{2,3}, {3,1}, {2}]
>>> [[counts.update({e: counts[e]+1}) for e in si] for si in sets]
[[None, None], [None, None], [None]]
>>> counts
{1: 5, 2: 7, 3: 10, 4: 2, 5: 9}
But yes, as others suggested, you can do it using Counter:
#1: use Counter to get new counts from sets
#2: merge both new & default counters
#3: get Counter back into your dictionary
With sample input:
>>> counts = {1:4, 2:5, 3:8, 4:2, 5:9}
>>> sets = [{2,3}, {3,1}, {2}]
>>> from collections import Counter
>>> cntr_new = Counter(x for s in sets for x in s)
>>> cntr_new
Counter({2: 2, 3: 2, 1: 1})
>>> cntr_orig = Counter(counts)
>>> cntr_final = cntr_orig + cntr_new
Final result:
>>> dict(cntr_final)
{1: 5, 2: 7, 3: 10, 4: 2, 5: 9}
gzip_files=["complete-credit-ctrl-txn-SE06_2013-07-17-00.log.gz","complete-credit-ctrl-txn-SE06_2013-07-17-01.log.gz"]
def input_func():
num = input("Enter the number of MIN series digits: ")
return num
for i in gzip_files:
import gzip
f=gzip.open(i,'rb')
file_content=f.read()
digit = input_func()
file_content = file_content.split('[')
series = [] #list of MIN
for line in file_content:
MIN = line.split('|')[13:15]
for x in MIN:
n = digit
x = x[:n]
series.append(x)
break
#count the number of occurences in the list named series
for i in series:
print i
#end count
Result:
63928
63928
63929
63929
63928
63928
That is only a part of the result. the actual result shows a really long list. Now i want to just list unique numbers and specify how many times it showed on the list.
So
63928 = 4,
63929 = 2
I would use a collections.Counter class here.
>>> a = [1, 1, 1, 2, 3, 4, 4, 5]
>>> from collections import Counter
>>> Counter(a)
Counter({1: 3, 4: 2, 2: 1, 3: 1, 5: 1})
Just pass your series variable to Counter and you'll get a dictionary where the keys are the unique elements and the values are their occurences in the list.
collections.Counter was introduced in Python 2.7. Use the following list comprehension for versions below 2.7
>>> [(elem, a.count(elem)) for elem in set(a)]
[(1, 3), (2, 1), (3, 1), (4, 2), (5, 1)]
You can then just convert this into a dictionary for easy access.
>>> dict((elem, a.count(elem)) for elem in set(a))
{1: 3, 2: 1, 3: 1, 4: 2, 5: 1}
You can use a Counter() for this.
So this will print what you need:
from collections import Counter
c = Counter(series)
for item,count in c.items():
print "%s = %s" % (item,count)
Compile a dictionary using unique numbers as keys, and their total occurrences as values:
d = {} #instantiate dictionary
for s in series:
# set default key and value if key does not exist in dictionary
d.setdefault(s, 0)
# increment by 1 for every occurrence of s
d[s] += 1
If this problem were any more complex. Implementation of map reduce (aka map fold) may be appropriate.
Map Reduce:
https://en.wikipedia.org/wiki/MapReduce
Python map function:
http://docs.python.org/2/library/functions.html#map
Python reduce function:
http://docs.python.org/2/library/functions.html#reduce
I need to unite two lists in Python3,where duplicates can exist,and for one set of these the resulting list will contain as many as max in both lists.An example might clarify it:
[1,2,2,5]( some operator)[2,5,5,5,9]=[1,2,2,5,5,5,9]
Ideas?
You can use the collections.Counter class:
>>> from collections import Counter
>>> combined = Counter([1,2,2,5]) | Counter([2,5,5,5,9])
>>> list(combined.elements())
[1, 2, 2, 5, 5, 5, 9]
It functions as a multiset (an unordered collection where each element can appear multiple times). The | operator gives you the union of the multisets, where each element appears max(apperances_in_counter1, appearances_in_counter2) times.
This class was added in Python 2.7 and 3.1.
Why use lists in the first place? That data looks like a dict to me:
[1,2,2,5] -> {1: 1, 2: 2, 5: 1}
[2,5,5,5,9] -> {2: 1, 5: 3, 9: 1}
Then it's simple:
keys = set(a.keys()+b.keys())
vals = [max(a.get(n, 0), b.get(n, 0)) for n in keys]
d = dict(zip(keys, vals))
print d
Result:
{1: 1, 2: 2, 5: 3, 9: 1}
Convert arrays to dictionaries with a[key] = count
Create new dictionary with rules c[key] = a.get(key, 0) > b.get(key, 0) and a[key] or b[key]. You need to iterate through both keys in a and in b dicts.
Expand dictionary, result += [value] * key
this is what I did. is there a better way in python?
for k in a_list:
if kvMap.has_key(k):
kvMap[k]=kvMap[k]+1
else:
kvMap[k]=1
Thanks
Use defaultdict
from collections import defaultdict
kvmap= defaultdict(int)
for k in a_list:
kvmap[k] += 1
Single element:
a_list.count(k)
All elements:
counts = dict((k, a_list.count(k)) for k in set(a_list))
I dunno, it basically looks fine to me. Your code is simple and easy to read which is an important part of what I consider pythonic.
You could trim it up a bit like so:
for k in a_list:
kvMap[k] = 1 + kvMap.get(k,0)
Such an old question, but considering that adding to a defaultdict(int) is such a common use, It should come as no surprise that collections has a special name for that (since Python 2.7)
>>> from collections import Counter
>>> Counter([1, 2, 1, 1, 3, 2, 3, 4])
Counter({1: 3, 2: 2, 3: 2, 4: 1})
>>> Counter("banana")
Counter({'a': 3, 'n': 2, 'b': 1})
Another solution exploits setdefault():
for k in a_list:
kvMap[k] = kvMap.setdefault(k, 0) + 1
If your list is sorted, an alternative way would be to use itertools.groupby. This might not be the most effective way, but it's interesting nonetheless. It retuns a dict of item > count :
>>> import itertools
>>> l = [1,1,2,3,4,4,4,5,5,6,6,6,7]
>>> dict([(key, len([e for e in group]))
for (key, group)
in itertools.groupby(l)])
{1: 2, 2: 1, 3: 1, 4: 3, 5: 2, 6: 3, 7: 1}