Given a list of integers, I want to check a second list and remove from the first only those which can not be made from the sum of two numbers from the second. So given a = [3,19,20]
and b = [1,2,17]
, I'd want [3,19]
.
Seems like a a cinch with two nested loops - except that I've gotten stuck with break
and continue
commands.
Here's what I have:
def myFunction(list_a, list_b):
for i in list_a:
for a in list_b:
for b in list_b:
if a + b == i:
break
else:
continue
break
else:
continue
list_a.remove(i)
return list_a
I know what I need to do, just the syntax seems unnecessarily confusing. Can someone show me an easier way? TIA!
Comments on code:
O(nm^2)
, where n
is the size of list_a
, and m
is the size of list_b
. This is pretty inefficient, but a good start to the problem. continue
and break
statements, which can lead to complicated code that is hard to debug. list_a
against list_b
. This is a way of splitting problems into smaller problems, and using them to solve the bigger problem. Overall I think your function is doing too much, and the logic could be condensed into much simpler code by breaking down the problem.
Another approach:
Since I found this task interesting, I decided to try it myself. My outlined approach is illustrated below.
1. You can first check if a list has a pair of a given sum in O(n)
time using hashing:
def check_pairs(lst, sums):
lookup = set()
for x in lst:
current = sums - x
if current in lookup:
return True
lookup.add(x)
return False
2. Then you could use this function to check if any any pair in list_b
is equal to the sum of numbers iterated in list_a
:
def remove_first_sum(list_a, list_b):
new_list_a = []
for x in list_a:
check = check_pairs(list_b, x)
if check:
new_list_a.append(x)
return new_list_a
Which keeps numbers in list_a
that contribute to a sum of two numbers in list_b
.
3. The above can also be written with a list comprehension:
def remove_first_sum(list_a, list_b):
return [x for x in list_a if check_pairs(list_b, x)]
Both of which works as follows:
>>> remove_first_sum([3,19,20], [1,2,17])
[3, 19]
>>> remove_first_sum([3,19,20,18], [1,2,17])
[3, 19, 18]
>>> remove_first_sum([1,2,5,6],[2,3,4])
[5, 6]
Note: Overall the algorithm above is O(n)
time complexity, which doesn't require anything too complicated. However, this also leads to O(n)
extra auxiliary space, because a set is kept to record what items have been seen.