How to iterate over and sum each item in a list with another to find a number?
I was doing some programming and this question came across, I got stuck with it somehow. I was given a list:
[10, 13, 15, 18, 20, 15]
And I had to find if the sum of any element in this would provide a result of 30 and the output should be a counter As we could see we have two possibilities: 10 + 20 = 30 and 15 + 15, so a counter is 2. But how to do it, should it be used for loop or itertools or any cut or functional solution?
source to share
You can use a itetools.combinations
generator expression in sum
:
>>> my_list=[10, 13, 15, 18, 20, 15]
>>> from itertools import combinations
>>> sum(i+j==30 for i,j in combinations(my_list,2))
2
And if you also want these elements to be able to use a list comprehension:
>>> [(i,j) for i,j in combinations(my_list,2) if i+j==30]
[(10, 20), (15, 15)]
source to share
Since this is due to a programming problem, here is a solution that has linear complexity in the length of the list (using combinations, you get quadratic complexity):
from collections import defaultdict
def count_pairs_summing_to(lst, n):
element_counter = defaultdict(int)
count = 0
for x in lst:
if (n - x) in element_counter:
count += element_counter[n - x]
element_counter[x] += 1
return count
The idea is to do one pass over the data and keep track of the elements we saw earlier in the hash table. When we see a new element x
, we only need to know if we have seen it before 30 - x
.
We also keep track of how many times we've seen each item to make sure we're counting duplicate pairs (for example, count_pairs_summing_to([10, 10, 20, 25], 30)
should return 2.).
Some benchmarking:
lst = [10, 13, 15, 18, 20, 15]
%timeit sum(i+j==30 for i,j in combinations(lst,2))
100000 loops, best of 3: 3.35 ยตs per loop
%timeit len([(ii,jj) for i, ii in enumerate(lst) for j, jj in enumerate(lst[i+1:]) if ii+jj==30])
100000 loops, best of 3: 6.59 ยตs per loop
%timeit count_pairs_summing_to(lst, 30)
100000 loops, best of 3: 2.92 ยตs per loop
# With a slightly bigger list.
import numpy.random as random
big_lst = list(random.randint(0, 100, size=1000))
%timeit len([(ii,jj) for i, ii in enumerate(big_lst) for j, jj in enumerate(big_lst[i+1:]) if ii+jj==30])
10 loops, best of 3: 125 ms per loop
%timeit sum(i+j==30 for i,j in combinations(big_lst,2))
1 loops, best of 3: 1.21 s per loop
# The previous one was surprisingly slow but it can be fixed:
%timeit sum(1 for i,j in combinations(big_lst,2) if i+j==30)
1 loops, best of 3: 88.2 ms per loop
%timeit count_pairs_summing_to(big_lst, 30)
1000 loops, best of 3: 504 ยตs per loop
source to share