Reputation: 13
I was working on part of a program in which I'm trying to input a list of numbers and return all groups of 3 numbers which sum to 0, without double or triple counting each number. Here's where I'm up to:
def threeSumZero2(array):
sums = []
apnd=[sorted([x,y,z]) for x in array for y in array for z in array if x+y+z==0]
for sets in apnd:
if sets not in sums:
sums.append(sets)
return sums
Is there any code I can put in the third line to make sure I don't return [0,0,0] as an answer.
This is my test list:
[-1,0,1,2,-1,4]
Thank you
*Edit: I should have clarified for repeated input values: the result expected for this test list is:
[[-1,-1,2],[-1,0,1]]
Upvotes: 0
Views: 241
Reputation: 22314
You want combinations without replacement, this is something offered by itertools
. Your sums
can then be made a set to remove the duplicates with regard to ordering.
from itertools import combinations
def threeSumZero2(array):
sums = set()
for comb in combinations(array, 3):
if sum(comb) == 0:
sums.add(tuple(sorted(comb)))
return sums
print(threeSumZero2([-1,0,1,2,-1,4]))
{(-1, -1, 2), (-1, 0, 1)}
This solution can also be written more concisely using a set-comprehension.
def threeSumZero2(nums):
return {tuple(sorted(comb)) for comb in combinations(nums, 3) if sum(comb) == 0}
Although, the above algorithm requires traversing all combinations of three items, which makes it O(n3).
A general strategy used for this kind of n-sum problem is to traverse the n-1 combinations and hash their sums, allowing to efficiently test them against the numbers in the list.
The algorithm complexity drops by one order of magnitude, making it O(n2)
from itertools import combinations
def threeSumZero2(nums, r=3):
two_sums = {}
for (i_x, x), (i_y, y) in combinations(enumerate(nums), r - 1):
two_sums.setdefault(x + y, []).append((i_x, i_y))
sums = set()
for i, n in enumerate(nums):
if -n in two_sums:
sums |= {tuple(sorted([nums[idx[0]], nums[idx[1]], n]))
for idx in two_sums[-n] if i not in idx}
return sums
print(threeSumZero2([-1,0,1,2,-1,4]))
{(-1, -1, 2), (-1, 0, 1)}
Upvotes: 3
Reputation: 20424
You could do this with itertools
(see Oliver's answer), but you can also achieve the result with three nested for-loops:
def threeSumZero2(lst):
groups = []
for i in range(len(lst)-2):
for j in range(i + 1, len(lst)-1):
for k in range(j + 1, len(lst)):
if lst[i] + lst[j] + lst[k] == 0:
groups.append((lst[i], lst[j], lst[k]))
return groups
and your test:
>>> threeSumZero2([-1, 0, 1, 2, -1, 4])
[(-1, 0, 1), (-1, 2, -1), (0, 1, -1)]
Oh and list
!= array
!
Upvotes: 0