【问题标题】:Python3 - All possible combinations of 3 variables that = xPython3 - = x 的 3 个变量的所有可能组合
【发布时间】:2018-02-06 00:38:04
【问题描述】:

我正在尝试找到所有可能的组合,其中 3 个变量可以 = 某个数字。

x = (10,11,12,13,14,15)
y = (10,11,12,13,14,15)
z = (10,11,12,13,14,15)
answer = 45

我将如何使用 itertools 找到每个组合

x + y + z = 45

在这种情况下,我希望 python 打印 (15,15,15) 但是,如果答案是 = 一个不同的数字,比如 30,它会打印 x、y、z 的每一个组合,当添加时 = 45。

【问题讨论】:

    标签: python python-3.x itertools


    【解决方案1】:

    您可以使用列表推导代替itertools

    x = (10,11,12,13,14,15)
    y = (10,11,12,13,14,15)
    z = (10,11,12,13,14,15)
    answer = 35
    
    res = [(i, j, answer - i - j) for i in x for j in y if (answer - i - j) in set(z)]
    
    print(res)
    

    正如@RoryDaulton 在 cmets 中指出的那样,如果answer-x-y 在@987654324 中,这种方法的优点是它是一种 O(n^2) 方法和 O(1) 查找时间相结合的测试方法@。对三个列表进行预排序,使z 成为最长的列表,应该会减少此操作所需的时间。

    我也测量了执行时间。测试清楚地表明 Paul 的代码是最快的:

    n = 100
    x, y, z = map(list, map(range, 3*(2 * n,)))
    any(map(random.shuffle, (x, y, z)))
    x, y, z = x[:n], y[:n], z[:n]
    answer = 4 * n
    
    def f1(): #team Ajax
        final_results = [i for i in itertools.product(x, y, z) if sum(i) == answer]
        return final_results
    
    def f2(): #team Pie
        res = [(i, j, answer - i - j) for i in x for j in y if (answer - i - j) in set(z)]
        return res
    
    def f3(): #team Paul
        xy = sorted(itertools.product(x, y), key=sum)
        xy = {k: list(v) for k, v in itertools.groupby(xy, sum)}
        xyz = [(a, b, c) for c in z for a, b in xy.get(answer-c, ())]
        return xyz
    
    repeats = 10
    print("f1", timeit.repeat("f1()", "from __main__ import f1", number = repeats))
    >>>f1 [1.741] #team Ajax
    print("f2", timeit.repeat("f2()", "from __main__ import f2", number = repeats))
    >>>f2 [0.221] #team Pie
    print("f3", timeit.repeat("f3()", "from __main__ import f3", number = repeats))
    >>>f3 [0.051] #team Paul
    

    (它只显示每个程序的最快值)

    【讨论】:

    • 这比查看所有三个元组的乘积更复杂,但速度更快:这个答案是O(n**2),但元组的乘积是顺序O(n**3),其中n 是长度的元组。 --我相信你知道这一点,但应该明确指出。
    • 在现实生活中,我会使用最长的列表作为z 并将其设置为一组,然后再运行此列表理解。您是否希望我将您的评论纳入您的评论并给予您信任?
    • 如果您想将我的评论纳入您的回答中,也许您会提供更多详细信息,请随意。
    • 感谢您的时间安排。
    【解决方案2】:

    你可以使用itertools.product:

    import itertools
    x = (10,11,12,13,14,15)
    y = (10,11,12,13,14,15)
    z = (10,11,12,13,14,15)
    answer = 45
    final_results = [i for i in itertools.product(x, y, z) if sum(i) == answer]
    

    输出:

    [(15, 15, 15)]
    

    【讨论】:

    • 一个小错字:itertools.product(x, y, y) -> itertools.product(x, y, z)
    • 正是我想要的! (我也修复了类型:D)
    【解决方案3】:

    这是一个itertools.productitertools.groupby 方法:

    >>> import random
    >>> import itertools
    >>> 
    # create random lists
    >>> x, y, z = map(list, map(range, 3*(20,)))
    >>> any(map(random.shuffle, (x, y, z)))
    False
    >>> x, y, z = x[:10], y[:10], z[:10]
    >>> 
    # choose a sum
    >>> sum_ = 40
    >>> 
    # compute and sort all sums of the first two
    >>> xy = sorted(itertools.product(x, y), key=sum)
    # and group by these sums
    >>> xy = {k: list(v) for k, v in itertools.groupby(xy, sum)}
    # use this to look up the matching x, y if any for each z
    >>> xyz = [(a, b, c) for c in z for a, b in xy.get(sum_-c, ())]
    >>> xyz
    [(18, 4, 18), (16, 6, 18), (6, 16, 18), (4, 18, 18), (5, 18, 17), (7, 16, 17), (18, 5, 17), (16, 7, 17), (16, 16, 8), (7, 18, 15), (18, 7, 15), (16, 9, 15), (5, 16, 19), (11, 10, 19), (18, 3, 19), (16, 5, 19), (18, 16, 6), (16, 18, 6), (11, 18, 11), (11, 16, 13), (18, 9, 13)]
    >>> 
    # validate
    >>> set(map(sum, xyz))
    {40}
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-09-11
      • 1970-01-01
      • 1970-01-01
      • 2018-03-31
      • 1970-01-01
      • 1970-01-01
      • 2023-03-24
      • 1970-01-01
      相关资源
      最近更新 更多