获取所有长度为 n 的 (n-choose-k) 组合

2025-01-03 08:40:00
admin
原创
90
摘要:问题描述:n如何从数字列表中获取所有长度组合(按顺序) ?例如,给定列表[1, 2, 3, 4]和设置n = 3,如何获得这些结果?[1, 2, 3] [1, 2, 4] [1, 3, 4] [2, 3, 4] 有关所有可能长度的组合,请参阅获取任意长度的列表元素的所有可能 (2^N) 组合。请注意,这不仅仅...

问题描述:

n如何从数字列表中获取所有长度组合(按顺序) ?例如,给定列表[1, 2, 3, 4]和设置n = 3,如何获得这些结果?

[1, 2, 3]
[1, 2, 4]
[1, 3, 4]
[2, 3, 4]

有关所有可能长度的组合,请参阅获取任意长度的列表元素的所有可能 (2^N) 组合。请注意,这不仅仅是迭代可能的长度并组合结果的问题,因为还有其他合理的方法可以解决该问题。

为了避免输入有重复元素时出现重复输出,请参阅无重复的 Python 组合。

相关内容:生成所有长度为 n 且设置了 k 位的二进制字符串


解决方案 1:

itertools可以这样做:

import itertools

for comb in itertools.combinations([1, 2, 3, 4], 3):
    print(comb)

输出:

(1, 2, 3)
(1, 2, 4)
(1, 3, 4)
(2, 3, 4)

解决方案 2:

添加递归函数:

def combinations(array, tuple_length, prev_array=[]):
    if len(prev_array) == tuple_length:
        return [prev_array]
    combs = []
    for i, val in enumerate(array):
        prev_array_extended = prev_array.copy()
        prev_array_extended.append(val)
        combs += combinations(array[i+1:], tuple_length, prev_array_extended)
    return combs

combinations([1, 2, 3, 4], 3)

输出:

[[1, 2, 3], 
[1, 2, 4], 
[1, 3, 4], 
[2, 3, 4]]

解决方案 3:

如果您不想一次计算所有组合,您可以创建一个返回长度为 n 的组合的生成器,如下所示:

def combinations(list_get_comb, length_combination):
    """ Generator to get all the combinations of some length of the elements of a list.

    :param list_get_comb: List from which it is wanted to get the combination of its elements.
    :param length_combination: Length of the combinations of the elements of list_get_comb.
    :return: Generator with the combinations of this list.
    """

    # Generator to get the combinations of the indices of the list
    def get_indices_combinations(sub_list_indices, max_index):
        """ Generator that returns the combinations of the indices

        :param sub_list_indices: Sub-list from which to generate ALL the possible combinations.
        :param max_index: Maximum index.
        :return:
        """
        if len(sub_list_indices) == 1:  # Last index of the list of indices
            for index in range(sub_list_indices[0], max_index + 1):
                yield [index]
        elif all([sub_list_indices[-i - 1] == max_index - i for i in
                  range(len(sub_list_indices))]):  # The current sublist has reached the end
            yield sub_list_indices
        else:
            for comb in get_indices_combinations(sub_list_indices[1:],
                                                 max_index):  # Get all the possible combinations of the sublist sub_list_indices[1:]
                yield [sub_list_indices[0]] + comb
            # Advance one position and check all possible combinations
            new_sub_list = []
            new_sub_list.extend([sub_list_indices[0] + i + 1 for i in range(len(sub_list_indices))])
            for new_comb in get_indices_combinations(new_sub_list, max_index):
                yield new_comb  # Return all the possible combinations of the new list

    # Start the algorithm:
    sub_list_indices = list(range(length_combination))
    for list_indices in get_indices_combinations(sub_list_indices, len(list_get_comb) - 1):
        yield [list_get_comb[i] for i in list_indices]

通过调用:

comb = combinations([1, 2, 3, 4], 3) 

next(comb)您可以通过调用或循环使用生成器来逐一计算长度为 3 的每个可能的组合: for c in comb:

这段代码的优点是,如果列表很长,可能的组合很多,而您想从所有可能的组合中得到一个符合某些条件的组合,您就不需要计算所有可能的组合,然后根据该条件进行筛选。您可以一个接一个地生成它们,直到找到符合您条件的组合。这将在计算上更加高效。另外,请注意,上面的代码只计算长度为 n 的组合,而不是计算所有可能的组合,然后根据长度进行筛选,这也使其更加高效。

但是,如果需要的话,您可以通过列出所有组合来一次计算它们list(comb)

解决方案 4:

此解决方案允许仅选择列表或集合的幂集子集,其元素数量介于用户定义的最小值和最大值之间。每个子集中的元素保持其原始顺序。要获得特定长度 n 的组合,请将元素的最小值和最大值都设置为所需值 n。

    def custom_power_set(s, min_cardinal=0, max_cardinal=None):
        """
        Returns a list of all subsets of a list or a set s 
        where the number of elements is between min_cardinal 
        and max_cardinal.
        """
        # Sets max_cardinal to cardinal of set s by default:
        if max_cardinal is None:
            max_cardinal = len(s)
    
        # In case s is a proper set:
        if type(s) == set:
            s = list(s)
    
        out = [[s[i] for i in range(len(s)) if (1 << i & j)]
               for j in range(1 << len(s))
               # condition re number of elements:
               if bin(j).count('1') in range(min_cardinal, max_cardinal + 1)]
    
        return out

例子:

    custom_power_set(range(4), 3, 3)

产生[[0, 1, 2], [0, 1, 3], [0, 2, 3], [1, 2, 3]]输出

解决方案 5:

除了出色的答案之外,如果您希望在实际开始处理组合之前了解组合的数量,这可能会有所帮助。如果您的代码动态地产生nk 的值,这可能会给您太多的组合而无法处理,或者如果您想估计运行时间、动态管理资源等,这可能会有所帮助。

例如 (400-choose-22) = 869220235645633221187116908079236800。这可能有点多,您可能需要以不同于 (4-choose-2) 的方式处理这种情况。

要计算金额,最好的方法是使用数学模块的梳理功能:

>>> import math
>>> n = 400
>>> k = 22
>>> math.comb(n,k)
869220235645633221187116908079236800
# let's not start calculations that won't finish before the sun blows up

使用此方法而不是以下简单方法的原因是:

>>> math.factorial(n)/math.factorial(k)*math.factorial(n-k)
# ...
OverflowError: integer division result too large for a float

前者使用与手动计算相同的阶乘减少。因此,虽然简单方法已经无法报告 (400-choose-22) 的数量,但 math.comb(n,k) 计算速度非常快,直到达到整数字符串转换的极限。此限制可以更改,但对于非常大的 n 和 k 值,检查 min(n/(nk), n/k) 是否足够接近 1 以成为您希望程序处理的组合数量可能更合理。

相关推荐
  政府信创国产化的10大政策解读一、信创国产化的背景与意义信创国产化,即信息技术应用创新国产化,是当前中国信息技术领域的一个重要发展方向。其核心在于通过自主研发和创新,实现信息技术应用的自主可控,减少对外部技术的依赖,并规避潜在的技术制裁和风险。随着全球信息技术竞争的加剧,以及某些国家对中国在科技领域的打压,信创国产化显...
工程项目管理   1572  
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   1355  
  信创产品在政府采购中的占比分析随着信息技术的飞速发展以及国家对信息安全重视程度的不断提高,信创产业应运而生并迅速崛起。信创,即信息技术应用创新,旨在实现信息技术领域的自主可控,减少对国外技术的依赖,保障国家信息安全。政府采购作为推动信创产业发展的重要力量,其对信创产品的采购占比情况备受关注。这不仅关系到信创产业的发展前...
信创和国产化的区别   0  
  信创,即信息技术应用创新产业,旨在实现信息技术领域的自主可控,摆脱对国外技术的依赖。近年来,国货国用信创发展势头迅猛,在诸多领域取得了显著成果。这一发展趋势对科技创新产生了深远的推动作用,不仅提升了我国在信息技术领域的自主创新能力,还为经济社会的数字化转型提供了坚实支撑。信创推动核心技术突破信创产业的发展促使企业和科研...
信创工作   0  
  信创技术,即信息技术应用创新产业,旨在实现信息技术领域的自主可控与安全可靠。近年来,信创技术发展迅猛,对中小企业产生了深远的影响,带来了诸多不可忽视的价值。在数字化转型的浪潮中,中小企业面临着激烈的市场竞争和复杂多变的环境,信创技术的出现为它们提供了新的发展机遇和支撑。信创技术对中小企业的影响技术架构变革信创技术促使中...
信创国产化   0  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用