这个问题已经问了很多遍了,但是我见过的每个SO帖子都希望值的长度是特定的,而我只是想知道每个唯一的组合,而不论长度如何。
下面的代码仅提供了一个列表,其中恰好有3个组合条目(它们不是唯一的)。
List<string> list = new List<string> { "003_PS", "003_DH", "003_HEAT" };
var perms = list.GetPermutations();
public static class Extensions
{
public static IEnumerable<IEnumerable<T>> GetPermutations<T>(this IEnumerable<T> items)
{
foreach (var item in items)
{
var itemAsEnumerable = Enumerable.Repeat(item, 1);
var subSet = items.Except(itemAsEnumerable);
if (!subSet.Any())
{
yield return itemAsEnumerable;
}
else
{
foreach (var sub in items.Except(itemAsEnumerable).GetPermutations())
{
yield return itemAsEnumerable.Union(sub);
}
}
}
}
}
/*
OUTPUT:
003_PS, 003_DH, 003_HEAT
003_PS, 003_HEAT, 003_DH
003_DH, 003_PS, 003_HEAT
003_DH, 003_HEAT, 003_PS
003_HEAT, 003_PS, 003_DH
003_HEAT, 003_DH, 003_PS
*/
我要的是这个东西
/*
OUTPUT:
003_PS, 003_DH, 003_HEAT
003_PS, 003_DH
003_PS, 003_HEAT
003_PS
003_DH, 003_HEAT
003_DH
003_HEAT
*/
大小不限于3个项目,每个条目都是唯一的。
此功能需要更改什么?我愿意使用LINQ解决方案
感谢您的帮助。谢谢!
编辑:以上列表输出不准确
**编辑#2: 这是我要寻找的Javascript版本。但是我不知道什么是C#等效语法:
function getUniqueList(arr){
if (arr.length === 1) return [arr];
else {
subarr = getUniqueList(arr.slice(1));
return subarr.concat(subarr.map(e => e.concat(arr[0])), [[arr[0]]]);
}
}
。
答案 0 :(得分:5)
好,您有n个项目,并且想要这些项目的2 n 个组合。
仅供参考,在设备上进行操作时称为“电源设备”;由于序列可以包含重复项,而集合不能包含重复项,因此您想要的不是精确幂集,但是它足够接近。如果您的序列包含重复项,那么我呈现的代码在某种意义上是错误的,因为我们会说{10, 10}
的结果将是{}, {10}, {10}, {10, 10}
,但是如果您不喜欢这样做,那么请删除在开始之前重复操作,然后您将在计算功率集。
计算所有组合的顺序非常简单。我们的理由如下:
让我们写代码:
using System;
using System.Collections.Generic;
using System.Linq;
static class Extensions
{
public static IEnumerable<T> Prepend<T>(
this IEnumerable<T> items,
T first)
{
yield return first;
foreach(T item in items)
yield return item;
}
public static IEnumerable<IEnumerable<T>> Combinations<T>(
this IEnumerable<T> items)
{
if (!items.Any())
yield return items;
else
{
var head = items.First();
var tail = items.Skip(1);
foreach(var sequence in tail.Combinations())
{
yield return sequence; // Without first
yield return sequence.Prepend(head);
}
}
}
}
public class Program
{
public static void Main()
{
var items = new [] { 10, 20, 30 };
foreach(var sequence in items.Combinations())
Console.WriteLine($"({string.Join(",", sequence)})");
}
}
然后我们得到输出
()
(10)
(20)
(10,20)
(30)
(10,30)
(20,30)
(10,20,30)
请注意,如果原始序列很长,此代码效率不高。
练习1:您明白为什么吗?
练习2:对于长序列,您能否在时间和空间上使此代码高效? (提示:如果您可以使head
,tail
和prepend
操作的内存效率更高,那将有很长的路要走。)
练习3:您在JavaScript中使用了相同的算法;可以在JS算法的各个部分和C#版本之间进行类比吗?
当然,我们假设原始序列中的项目数很短。如果是一百,您将要等待很长的时间来枚举所有数万亿个组合。
如果要获得具有特定数量元素的所有组合 ,请参阅我有关该算法的系列文章:https://ericlippert.com/2014/10/13/producing-combinations-part-one/