I have a dictionary of Counters, e.g:
from collections import Counter, defaultdict
numbers = defaultdict(Counter)
numbers['a']['first'] = 1
numbers['a']['second'] = 2
numbers['b']['first'] = 3
I want to get the sum: 1+2+3 = 6
What would be the simplest / idiomatic way to do this in python 3?
Use a nested comprehension:
sum(x for counter in numbers.values() for x in counter.values())
Or sum first the counters (starting with an empty one), and then their values:
sum(sum(numbers.values(), Counter()).values())
Or first each counter's values, and then the intermediate results:
sum(sum(c.values()) for c in numbers.values())
Or use chain:
from itertools import chain
sum(chain.from_iterable(d.values() for d in numbers.values()))
I prefer the first way.
sum(sum(c.values()) for c in numbers.values())
from itertools import chain
sum(chain.from_iterable(d.values() for d in numbers.values()))
# outputs: 6
In terms of performance use .itervalues() in python 2.x, that avoids building intermediary list (applies to all solutions here).
sum(chain.from_iterable(d.itervalues() for d in numbers.itervalues()))
Related
I know how to create a new list based on the values of an existing list, eg casting
numspec = [float(x) for x in textspec]
Now I have a list of numbers where I need to subtract a value based on the index of a list. I have calculated an a and b value and ended up doing
peakadj = []
for i in range(len(peakvalues)):
val=peakvalues[i]-(i*a+b)
peakadj.append(val)
This works, but I don't like the feel of it, is there any more pythonic way of doing this?
Use the builtin enumerate function and a list comprehension.
peakadj = [val-(i*a+b) for i, val in enumerate(peakvalues)]
Perhaps faster:
from itertools import count
peakadj = [val-iab for val, iab in zip(peakvalues, count(b, a))]
Or:
from itertools import count
from operator import sub
peakadj = [*map(sub, peakvalues, count(b, a))]
Little benchmark
Consider this list of sets
my_input_list= [
{1,2,3,4,5},
{2,3,7,4,5},
set(),
{1,2,3,4,5,6},
set(),]
I want to get the only exclusive elements 6 and 7 as the response, list or set. Set preferred.
I tried
print reduce(set.symmetric_difference,my_input_list) but that gives
{2,3,4,5,6,7}
And i tried sorting the list by length, smallest first raises an error due to two empty sets. Largest first gives the same result as unsorted.
Any help or ideas please?
Thanks :)
Looks like the most straightforward solution is to count everything and return the elements that only appear once.
This solution uses chain.from_iterable (to flatten your sets) + Counter (to count things). Finally, use a set comprehension to filter elements with count == 1.
from itertools import chain
from collections import Counter
c = Counter(chain.from_iterable(my_input_list))
print({k for k in c if c[k] == 1})
{6, 7}
A quick note; the empty literal {} is used to indicate an empty dict, not set. For the latter, use set().
You could use itertools.chain and collection.Counter:
from itertools import chain
from collections import Counter
r = {k for k,v in Counter(chain.from_iterable(my_input_list)).items() if v==1}
Let say that I have n lists and they are not disjoint. I want to make every combination of n elements which I get one from every lists I have but in that combination there are different elements and there are no double combination. So, [1,1,2] isn't allowed and [1,2,3] is same as [2,1,3].
For example, I have A=[1,2,3], B=[2,4,1], and C=[1,5,3]. So, the output that I want is [[1,2,5],[1,2,3],[1,4,5],[1,4,3],[2,4,1],[2,4,5],[2,4,3],[3,2,5],[3,4,5],[3,1,5]].
I have search google and I think function product in module itertools can do it. But, I have no idea how to make no same elements in every combinations and no double combinations.
Maybe something like:
from itertools import product
A=[1,2,3]
B=[2,4,1]
C=[1,5,3]
L = list(set([ tuple(sorted(l)) for l in product(A,B,C) if len(set(l))==3 ]))
Of course you would have to change 3 ot the relevant value if you work with more than 3 lists.
how about this? create a dicitonary with the sorted permutations as key. accept values only if all the three integers are different:
from itertools import product
A=[1,2,3]
B=[2,4,1]
C=[1,5,3]
LEN = 3
dct = {tuple(sorted(item)): item for item in product(A,B,C)
if len(set(item)) == LEN}
print(dct)
vals = list(dct.values())
print(vals)
What is the best way of establishing the sum of all counts in a collections.Counter object?
I've tried:
sum(Counter([1,2,3,4,5,1,2,1,6]))
but this gives 21 instead of 9?
The code you have adds up the keys (i.e. the unique values in the list: 1+2+3+4+5+6=21).
To add up the counts, use:
In [4]: sum(Counter([1,2,3,4,5,1,2,1,6]).values())
Out[4]: 9
This idiom is mentioned in the documentation, under "Common patterns".
Sum the values:
sum(some_counter.values())
Demo:
>>> from collections import Counter
>>> c = Counter([1,2,3,4,5,1,2,1,6])
>>> sum(c.values())
9
Starting in Python 3.10, Counter is given a total() function which provides the sum of the counts:
from collections import Counter
Counter([1,2,3,4,5,1,2,1,6]).total()
# 9
sum(Counter([1,2,3,4,5,1,2,1,6]).values())
I want count the same elements of two lists. Lists can have duplicate elements, so I can't convert this to sets and use & operator.
a=[2,2,1,1]
b=[1,1,3,3]
set(a) & set(b) work
a & b don't work
It is possible to do it withoud set and dictonary?
In Python 3.x (and Python 2.7, when it's released), you can use collections.Counter for this:
>>> from collections import Counter
>>> list((Counter([2,2,1,1]) & Counter([1,3,3,1])).elements())
[1, 1]
Here's an alternative using collections.defaultdict (available in Python 2.5 and later). It has the nice property that the order of the result is deterministic (it essentially corresponds to the order of the second list).
from collections import defaultdict
def list_intersection(list1, list2):
bag = defaultdict(int)
for elt in list1:
bag[elt] += 1
result = []
for elt in list2:
if elt in bag:
# remove elt from bag, making sure
# that bag counts are kept positive
if bag[elt] == 1:
del bag[elt]
else:
bag[elt] -= 1
result.append(elt)
return result
For both these solutions, the number of occurrences of any given element x in the output list is the minimum of the numbers of occurrences of x in the two input lists. It's not clear from your question whether this is the behavior that you want.
Using sets is the most efficient, but you could always do r = [i for i in l1 if i in l2].
SilentGhost, Mark Dickinson and Lo'oris are right, Thanks very much for report this problem - I need common part of lists, so for:
a=[1,1,1,2]
b=[1,1,3,3]
result should be [1,1]
Sorry for comment in not suitable place - I have registered today.
I modified yours solutions:
def count_common(l1,l2):
l2_copy=list(l2)
counter=0
for i in l1:
if i in l2_copy:
counter+=1
l2_copy.remove(i)
return counter
l1=[1,1,1]
l2=[1,2]
print count_common(l1,l2)
1