值列表的所有可能组合
我的 C# 程序中有一个整数列表 List
。但是,我仅在运行时知道列表中的项目数量。
假设为了简单起见,我的列表是 {1, 2, 3}
现在我需要生成所有可能的组合,如下所示。
{1, 2, 3}
{1, 2}
{1, 3}
{2, 3}
{1}
{2}
{3}
有人可以帮忙解决这个问题吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(20)
这是使用递归的通用解决方案
我知道这是一篇旧文章,但有人可能会发现这很有帮助。
Here's a generic solution using recursion
I know this is an old post, but someone might find this helpful.
另一个使用 Linq 和递归的解决方案......
Another solution using Linq and recursion...
这是对 @ojlovecd 答案的改进,无需使用字符串。
This is an improvement of @ojlovecd answer without using strings.
首先,给定一组 n 个元素,计算其中 k 个元素的所有组合 (nCk)。您必须将 k 的值从 1 更改为 n 以满足您的要求。
请参阅此 codeproject 文章,了解用于生成组合的 C# 代码。
如果您有兴趣自己开发组合算法,请检查此 SO问题,其中有很多相关材料的链接。
Firstly, given a set of n elements, you compute all combinations of k elements out of it (nCk). You have to change the value of k from 1 to n to meet your requirement.
See this codeproject article for C# code for generating combinations.
In case, you are interested in developing the combination algorithm by yourself, check this SO question where there are a lot of links to the relevant material.
这对我有用,它稍微复杂一些,实际上需要一个比较器回调函数,它实际上是 2 个函数,区别在于 AllCombos 显式添加单个项目列表。它非常原始,绝对可以修剪,但它可以完成工作。欢迎任何重构建议。谢谢,
This worked for me, it's slightly more complex and actually takes a comparer callback function, and it's actually 2 functions, the difference being that the AllCombos adds the single item lists explicitly. It is very raw and can definitely be trimmed down but it gets the job done. Any refactoring suggestions are welcome. Thanks,
我们可以使用递归来解决涉及字符串或整数的组合/排列问题。
We can use recursion for combination/permutation problems involving string or integers.
怎么样
What about
使用 C# 7 的 Linq 的稍微更通用的版本。这里按具有两个元素的项目进行过滤。
A slightly more generalised version for Linq using C# 7. Here filtering by items that have two elements.
我是这样做的。
您将其称为:
Here is how I did it.
You call it as :
我刚刚遇到一种情况,我需要这样做,这就是我想到的:
它可能不太有效,而且它确实有改进的空间,但可以完成工作!
I just run into a situation where I needed to do this, this is what I came up with:
It may be not too efficient, and it sure has room for improvement, but gets the job done!
这是基于使用扩展方法的
ojlovecd
答案的改进版本:用法:
输出:
这个想法基本上是使用一些标志来跟踪哪些项目已添加到组合中。所以在 1, 2 & 的情况下3、生成以下二进制字符串以指示是否应包含或排除某项:
001、010、011、100、101、110 和111
This is an improved version based on the answer from
ojlovecd
using extension methods:Usage:
Output:
The idea is to basically use some flags to keep track of which items were already added to the combination. So in case of 1, 2 & 3, the following binary strings are generated in order to indicate whether an item should be included or excluded:
001, 010, 011, 100, 101, 110 & 111
我想推荐一种我认为非常直观且易于阅读的方法。 (注意:它比当前接受的解决方案慢。)
它建立在这样的想法上:对于列表中的每个整数,我们需要使用
在这里,我使用
.Aggregate()
和一个IEnumerable>
种子,其中包含单个空集合条目。这个空条目让我们可以轻松地同时执行上述两个步骤。在聚合所得组合集合后,可以跳过空集合条目。它是这样的:
对于输入整数列表
{ 1, 2, 3 }
中的每个条目,累积过程如下:next = 1
next = 2
next = 3
跳过第一个(空)条目,我们剩下以下集合:
,可以轻松地按集合长度和集合条目总和进行排序,以获得更清晰的概览。
小提琴示例此处。
I'd like to suggest an approach that I find to be quite intuitive and easy to read. (Note: It is slower than the currently accepted solution.)
It is built on the idea that for each integer in the list, we need to extend the so-far-aggregated resulting combination list with
Here, I am using
.Aggregate()
with a seed that is anIEnumerable<IEnumerable<int>>
containing a single, empty collection entry. That empty entry lets us easily do the two steps above simultaneously. The empty collection entry can be skipped after the resulting combination collection has been aggregated.It goes like this:
For each entry in the input integer list
{ 1, 2, 3 }
, the accumulation progresses as follows:next = 1
next = 2
next = 3
Skipping the first (empty) entry, we are left with the following collection:
, which can easily be ordered by collection length and collection entry sum for a clearer overview.
Example fiddle here.
这里的一些解决方案确实很巧妙;尤其是那些使用位图的。
但我发现,在实践中,
所以我决定写一些不像这里其他人那么聪明的东西。
我更基本的方法认为,
Variations(1 to maxLength)
集合只是每个长度1
到maxLength
的所有固定长度变体的 UNION。 code>:即
,您可以为每个所需的长度执行“从 N 中选择 K”(
对于 (1, 2, 3, ..., maxLength) 中的每个 K
),然后只需执行将这些单独的结果合并起来产生一个列表列表。由此产生的代码旨在易于理解和维护:
很高兴收到评论(好的和坏的)。也许有一种更简洁的方法可以在 LINQ 中实现这一目标?也许这里真正聪明的人可以将他们的方法与我更基本的方法结合起来?
Some of the solutions here are truly ingenious; especially the ones that use bitmaps.
But I found that in practice these algos
So I decided to write something not as clever as the other people here.
My more basic approach recognises that the set of
Variations(1 to maxLength)
is simply a UNION of all fixed-length Variations of each length1
tomaxLength
:i.e
So you can do a "choose K from N" for each required length (
for each K in (1, 2, 3, ..., maxLength)
) and then just do a Union of these separate results to yield a List of Lists.This resulting code intends to be easy to understand and to maintain:
Happy to receive comments (good and bad). Maybe there's a more succint way to achieve this in LINQ? Maybe the really smart people here can marry their approach with my more basic one?
这是 jaolho 解决方案的一个变体,通过按位运算进行优化以获得更好的性能
this is a variant of the jaolho's solution, optimized with bitwise operations for better performance
请找到非常非常简单的解决方案,无需递归且不占用内存。
独特组合
Please find very very simple solution without recursion and which dont eat RAM.
Unique Combinations
试试这个:
try this:
假设初始集合中的所有项都是不同,我们可以尝试使用Linq来查询;让我们概括一下解决方案:
代码:
演示:
结果:
如果您想排除初始空数组,请输入
.Range(1, (1 << (data.Length)) - 1)
而不是.Range(0, 1 << (data.Length))
代码>算法说明:
拥有
collection.Length
不同项的集合,我们得到2 ** collection.Length
组合(我们可以将其计算为1 << collection.Length
):要生成所有掩码,我们可以直接使用
Enumerable.Range(0, 1 << (data.Length))
Linq 查询。现在有了index
掩码,当且仅当index
中的相应位设置为1
时,我们才应该从集合中获取项目:代码可以在
这里对于集合
data
中的每个项目 (v
),我们检查index
中是否设置了第i
位(面具)。Assuming that all items within the initial collection are distinct, we can try using Linq in order to query; let's generalize the solution:
Code:
Demo:
Outcome:
If you want to exclude the initial empty array, put
.Range(1, (1 << (data.Length)) - 1)
instead of.Range(0, 1 << (data.Length))
Algorithm explanation:
Having a collection of
collection.Length
distinct items we get2 ** collection.Length
combinations (we can compute it as1 << collection.Length
):To generate all masks we can use direct
Enumerable.Range(0, 1 << (data.Length))
Linq query. Now havingindex
mask we should take item from the collection if and only if corresponding bit withinindex
is set to1
:The code can be
here for each item (
v
) in the collectiondata
we check ifi
-th bit is set in theindex
(mask).以下是强类型列表的两个通用解决方案,它们将返回列表成员的所有唯一组合(如果您可以用更简单的代码解决此问题,我向您致敬):
Here are two generic solutions for strongly typed lists that will return all unique combinations of list members (if you can solve this with simpler code, I salute you):
这个答案使用与 ojlovecd 和(对于他的迭代解决方案)jaolho 相同的算法。我唯一要添加的是一个选项,用于过滤结果以获取组合中最少数量的项目。例如,如果您只对包含至少两个项目的组合感兴趣,这可能很有用。
编辑:根据@user3610374的要求,添加了最大项目数过滤器。
编辑 2:正如 @stannius 所建议的,该算法已被更改,以使其在不需要所有组合的情况下更加有效。
This answer uses the same algorithm as ojlovecd and (for his iterative solution) jaolho. The only thing I'm adding is an option to filter the results for a minimum number of items in the combinations. This can be useful, for example, if you are only interested in the combinations that contain at least two items.
Edit: As requested by @user3610374 a filter for the maximum number of items has been added.
Edit 2: As suggested by @stannius the algorithm has been changed to make it more efficient for cases where not all combinations are wanted.