简体   繁体   中英

Find 4 numbers which sum is given number

Need to find 4 numbers from list which sum will be equal to given "sum_"

def find_four(nums, sum_):
    if len(nums) < 4:
        return
    i = 0
    i2 = 1
    i3 = 2
    i4 = 3
    while True:
        num_sum = nums[i] + nums[i2] + nums[i3] + nums[i4]
        if num_sum == sum_:
            return [nums[i], nums[i2], nums[i3], nums[i4]]
        elif i == len(nums) - 4:
            return
        elif i2 == len(nums) - 3:
            i += 1
        elif i3 == len(nums) - 2:
            i2 += 1
        elif i4 == len(nums) - 1:
            i3 += 1
        elif i4 != len(nums):
            i4 += 1

My code works good with some lists like: find_four([1, 1, 1, 5, 1, 5, 7], 10) or find_four([4, 6, 1, 4, 1, 6, 2], 13) . But it don't work with some for example' find_four([7, 5, 1, 4, 1, 6, 2], 11) (need to print 7, 1, 1, 2 ) What is wrong ?? :(

There's no reason for nested loops.

import itertools
import operator as op
from functools import reduce

def find_N(nums, target, N=4):
    for combo in list(itertools.combinations(nums, N)):
        if reduce(op.add, combo) == target:
            return combo
    return []

>>> find_N([1,2,3,4,5,6,7,8], target=10)
(1, 2, 3, 4)

>>> find_N([1,2,3,4,5,6,7,8], target=10, N=3)
(1, 2, 7)

>>> find_N([1,2,3,4,5,6,7,8], target=10, N=2)
(2, 8)

Observations:

  • Many things are pre-built in Python, use them instead of recreating the wheel
  • Generalization is good. You don't want to change your function if N changes from 4
  • sum isn't a sound variable name as it clobbers the built-in function of that name

You should probably sort nums before processing it in chunks of 4, as you're doing.

def find_four(nums, sum_):
    if len(nums) < 4:
        return
    nums = sorted(nums)  # Sort nums here
    i = 0
    i2 = 1
    i3 = 2
    i4 = 3
    while True:
        num_sum = nums[i] + nums[i2] + nums[i3] + nums[i4]
        if num_sum == sum_:
            return [nums[i], nums[i2], nums[i3], nums[i4]]
        elif i == len(nums) - 4:
            return
        elif i2 == len(nums) - 3:
            i += 1
        elif i3 == len(nums) - 2:
            i2 += 1
        elif i4 == len(nums) - 1:
            i3 += 1
        elif i4 != len(nums):
            i4 += 1

This will produce for 7, 1, 1, 2 for find_four([7, 5, 1, 4, 1, 6, 2], 11) . Note that the order of the numbers will not be preserved.

Simply use itertools.combinations . Below code will return all pairs from which has summation equals to sum_. I am setting combinations to take 4 numbers by passing 4 default in the argument. You can alternate amount of numbers used for calculating sum by changing target.

import itertools
from itertools import combinations
def find_four(nums, sum_,target=4):
    return([pair for pair in itertools.combinations(nums,target) if sum(pair) == sum_])

nums=[1,2,3,4,1,5,6,7,8,9,10,11,12]

example:-

>>> find_four([1,2,3,4,1,5,6,7,8,9,10,11,12],10)
[(1, 2, 3, 4), (1, 2, 1, 6), (1, 3, 1, 5), (2, 3, 4, 1)]
>>>find_four([1,2,3,4,1,5,6,7,8,9,10,11,12],10,3)
[(1, 2, 7), (1, 3, 6), (1, 4, 5), (1, 1, 8), (2, 3, 5), (2, 1, 7), (3, 1, 6), (4, 1, 5)]

You can do this simpler using 4 loops

def find_four(arr, sum_):
    for i in range(len(arr)):
        for j in range(i + 1, len(arr)):
            for t in range(j + 1, len(arr)):
                for k in range(t + 1, len(arr)):
                    if arr[i] + arr[j] + arr[t] + arr[k] == sum_:
                        return [arr[i],arr[j],arr[t],arr[k]]
    return []

Input

find_four([1, 1, 1, 5, 1, 5, 7], 10)
find_four([4, 6, 1, 4, 1, 6, 2], 13)
find_four([7, 5, 1, 4, 1, 6, 2], 11)

Output

[1, 1, 1, 7]
[4, 6, 1, 2]
[7, 1, 1, 2]

I notice that each collection of numbers in the question is a bag or multiset , rather than a set. That is, each collection contains at least one repetition of one of its members. This guaranteed to be the case, it can be more appropriate to calculate all multiset combinations and thereby avoid processing repeated combinations.

>>> from sympy.utilities.iterables import multiset_combinations
>>> def find_four(nums, sum_):
...     for c in multiset_combinations(nums, 4):
...         if sum(c) == sum_:
...             return c
...     return {}
... 
>>> find_four([1, 1, 1, 5, 1, 5, 7], 10)
[1, 1, 1, 7]
>>> find_four([4, 6, 1, 4, 1, 6, 2], 13)
[1, 2, 4, 6]
>>> find_four([7, 5, 1, 4, 1, 6, 2], 11)
[1, 1, 2, 7]

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM