C# 如何获取数组的所有子集?

C# 如何获取数组的所有子集?,c#,arrays,C#,Arrays,给定一个数组:[狗、猫、鼠标] 最优雅的创作方式是什么: [,,] [,,mouse] [,cat,] [,cat,mouse] [dog,,] [dog,,mouse] [dog,cat,] [dog,cat,mouse] 我需要这个为任何大小的阵列工作 这本质上是一个二进制计数器,其中数组索引表示位。这可能让我可以使用一些按位操作进行计数,但我看不到将其转换为数组索引的好方法。string[]source=new string[]{“dog”、“cat”、“mouse”}; static

给定一个数组:
[狗、猫、鼠标]

最优雅的创作方式是什么:

[,,]
[,,mouse]
[,cat,]
[,cat,mouse]
[dog,,]
[dog,,mouse]
[dog,cat,]
[dog,cat,mouse]
我需要这个为任何大小的阵列工作

这本质上是一个二进制计数器,其中数组索引表示位。这可能让我可以使用一些按位操作进行计数,但我看不到将其转换为数组索引的好方法。

string[]source=new string[]{“dog”、“cat”、“mouse”};
static IEnumerable<IEnumerable<T>> GetSubsets<T>(IList<T> set)
{
    var state = new BitArray(set.Count);
    do
        yield return Enumerable.Range(0, state.Count)
                               .Select(i => state[i] ? set[i] : default(T));
    while (Increment(state));
}

static bool Increment(BitArray flags)
{
    int x = flags.Count - 1; 
    while (x >= 0 && flags[x]) flags[x--] = false ;
    if (x >= 0) flags[x] = true;
    return x >= 0;
}
for(inti=0;i
好的,我被告知上面的答案行不通。如果你看重优雅而不是效率,我会在我蹩脚的伪代码中尝试递归:

Array_Of_Sets subsets(Array a) 
{
    if (a.length == 0) 
         return [new Set();] // emptyset
    return subsets(a[1:]) + subsets(a[1:]) . map(lambda x |> x.add a[0]) 
}

根据您的构思,这里有一个简单易行的解决方案:

private static void Test()
{
    string[] test = new string[3] { "dog", "cat", "mouse" };

    foreach (var x in Subsets(test))
        Console.WriteLine("[{0}]", string.Join(",", x));
}

public static IEnumerable<T[]> Subsets<T>(T[] source)
{
    int max = 1 << source.Length;
    for (int i = 0; i < max; i++)
    {
        T[] combination = new T[source.Length];

        for (int j = 0; j < source.Length; j++)
        {
            int tailIndex = source.Length - j - 1;
            combination[tailIndex] =
                ((i & (1 << j)) != 0) ? source[tailIndex] : default(T);
        }

        yield return combination;
    }
}
private静态无效测试()
{
string[]test=新字符串[3]{“dog”、“cat”、“mouse”};
foreach(子集中的var x(测试))
Console.WriteLine(“[{0}]”,string.Join(“,”,x));
}
公共静态IEnumerable子集(T[]源)
{

int max=1您可以使用
位数组
类轻松访问数字中的位:

string[] animals = { "Dog", "Cat", "Mouse" };
List<string[]> result = new List<string[]>();
int cnt = 1 << animals.Length;
for (int i = 0; i < cnt; i++) {
   string[] item = new string[animals.Length];
   BitArray b = new BitArray(i);
   for (int j = 0; j < item.Length; j++) {
      item[j] = b[j] ? animals[j] : null;
   }
   result.Add(item);
}
string[]动物={“狗”、“猫”、“老鼠”};
列表结果=新列表();

int cnt=1这是上述Mehrdad溶液的一个小变化:

static IEnumerable<T[]> GetSubsets<T>(T[] set) {
    bool[] state = new bool[set.Length+1];
    for (int x; !state[set.Length]; state[x] = true ) {
        yield return Enumerable.Range(0, state.Length)
                               .Where(i => state[i])
                               .Select(i => set[i])
                               .ToArray();
        for (x = 0; state[x]; state[x++] = false);
    }
}
静态IEnumerable GetSubset(T[]集){
bool[]状态=新bool[set.Length+1];
for(int x;!state[set.Length];state[x]=true){
产生返回可枚举范围(0,state.Length)
.其中(i=>状态[i])
.选择(i=>设置[i])
.ToArray();
for(x=0;状态[x];状态[x++]=false);
}
}
还是用指针

static IEnumerable<T[]> GetSubsets<T>(T[] set) {
    bool[] state = new bool[set.Length+1];
    for (bool *x; !state[set.Length]; *x = true ) {
        yield return Enumerable.Range(0, state.Length)
                               .Where(i => state[i])
                               .Select(i => set[i])
                               .ToArray();
        for (x = state; *x; *x++ = false);
    }
}
静态IEnumerable GetSubset(T[]集){
bool[]状态=新bool[set.Length+1];
对于(bool*x;!state[set.Length];*x=true){
产生返回可枚举范围(0,state.Length)
.其中(i=>状态[i])
.选择(i=>设置[i])
.ToArray();
for(x=状态;*x;*x++=false);
}
}

优雅?为什么不去试试呢

    public static IEnumerable<IEnumerable<T>> SubSetsOf<T>(IEnumerable<T> source)
    {
        if (!source.Any())
            return Enumerable.Repeat(Enumerable.Empty<T>(), 1);

        var element = source.Take(1);

        var haveNots = SubSetsOf(source.Skip(1));
        var haves = haveNots.Select(set => element.Concat(set));

        return haves.Concat(haveNots);
    }
公共静态IEnumerable子集(IEnumerable源)
{
如果(!source.Any())
返回Enumerable.Repeat(Enumerable.Empty(),1);
var元素=源。取(1);
var haveNots=子集合(source.Skip(1));
var haves=haveNots.Select(set=>element.Concat(set));
有返回权者(无返回权者);
}

这里有一个类似于David B的方法的解决方案,但如果确实需要使用原始元素数(即使是空的)返回集合,则可能更合适:

static public List getsubset(IEnumerable originalList)
{
if(originalList.Count()==0)
返回新列表(){new List()};
var setsFound=新列表();
foreach(getSubset中的var列表(originalList.Skip(1)))
{                
setsfund.Add(originalist.Take(1.Concat(list.ToList());
Add(newlist(){default(T)}.Concat(List.ToList());
}
发现退货;
}

如果您传入一个包含三个字符串的列表,您将返回八个列表,每个列表包含三个元素(但有些元素将为空)。

Guffa的回答具有我正在搜索的基本功能,但是行中包含

BitArray b = new BitArray(i);
对我不起作用,它给出了ArgumentOutOfRangeException。以下是我稍微调整的工作代码:

string[] array = { "A", "B", "C","D" };
int count = 1 << array.Length; // 2^n

for (int i = 0; i < count; i++)
{
    string[] items = new string[array.Length];
    BitArray b = new BitArray(BitConverter.GetBytes(i));
    for (int bit = 0; bit < array.Length; bit++) {
        items[bit] = b[bit] ? array[bit] : "";
    }
    Console.WriteLine(String.Join("",items));
}
string[]数组={“A”、“B”、“C”、“D”};

int count=1这里是mqp的一个变体,它使用状态a而不是
int
,以避免包含30个以上元素的集合溢出:

using System.Numerics;

public static IEnumerable<IEnumerable<T>> GetSubsets<T>(IList<T> source)
{
    BigInteger combinations = BigInteger.One << source.Count;
    for (BigInteger i = 0; i < combinations; i++)
    {
        yield return Enumerable.Range(0, source.Count)
            .Select(j => (i & (BigInteger.One << j)) != 0 ? source[j] : default);
    }
}
使用系统数值;
公共静态IEnumerable GetSubset(IList源)
{

BigInteger组合=BigInteger.One(i&(BigInteger.One易于理解的版本(带说明)

我假设source={1,2,3,4}

public static IEnumerable<IEnumerable<T>> GetSubSets<T>(IEnumerable<T> source)
    {
        var result = new List<IEnumerable<T>>() { new List<T>() }; // empty cluster  added

        for (int i = 0; i < source.Count(); i++)
        {
            var elem = source.Skip(i).Take(1);

            // for elem = 2
            // and currently result = [ [],[1] ]
            var matchUps = result.Select(x => x.Concat(elem));
            //then matchUps => [ [2],[1,2] ]

             result = result.Concat(matchUps).ToList();
            //  matchUps and result concat operation
            // finally result = [ [],[1],[2],[1,2] ]
        }
        return result;
    }
公共静态IEnumerable GetSubset(IEnumerable源)
{
var result=new List(){new List()};//添加了空集群
对于(int i=0;ix.Concat(elem));
//然后匹配=>[[2],[1,2]]
result=result.Concat(matchUps.ToList();
//匹配和结果concat操作
//最终结果=[],[1],[2],[1,2]]
}
返回结果;
}

按照编写方式,它更多地是一个乘积(笛卡尔积),而不是所有子集的列表

您有三套:
(空,“狗”),(空,“猫”),(空,“鼠标”)

关于产品的一般解决方案,有几篇文章。不过,正如前面提到的,因为每个轴实际上只有两个选择,所以一个位可以表示项目的存在与否


因此,集合的总集合是从
0
2^N-1
的所有数字。如果
N<31
一个int将起作用。

所有答案似乎都没有你想要的优雅,当你等待答案时,检查集合的所有子集S==S的“幂集”。问题明确提到:“给定任何大小的数组。”更新到一个更通用的版本。选择这个作为它的简洁和切中要害,也可能比Linq或列表“可能”更有效,在这个例子中是“我太懒了,无法测量它”的缩写如果我在源代码中再添加一个字符串,这将不起作用。因为您只使用了3个组合作为输出。如果我知道C#,我会写这个答案!但只要对增量的工作方式做一点小小的更改,它仍然可以变得更好。我将在下面发布它,因为它不适合注释。我编写了o
BitArray b = new BitArray(i);
string[] array = { "A", "B", "C","D" };
int count = 1 << array.Length; // 2^n

for (int i = 0; i < count; i++)
{
    string[] items = new string[array.Length];
    BitArray b = new BitArray(BitConverter.GetBytes(i));
    for (int bit = 0; bit < array.Length; bit++) {
        items[bit] = b[bit] ? array[bit] : "";
    }
    Console.WriteLine(String.Join("",items));
}
using System.Numerics;

public static IEnumerable<IEnumerable<T>> GetSubsets<T>(IList<T> source)
{
    BigInteger combinations = BigInteger.One << source.Count;
    for (BigInteger i = 0; i < combinations; i++)
    {
        yield return Enumerable.Range(0, source.Count)
            .Select(j => (i & (BigInteger.One << j)) != 0 ? source[j] : default);
    }
}
public static IEnumerable<IEnumerable<T>> GetSubSets<T>(IEnumerable<T> source)
    {
        var result = new List<IEnumerable<T>>() { new List<T>() }; // empty cluster  added

        for (int i = 0; i < source.Count(); i++)
        {
            var elem = source.Skip(i).Take(1);

            // for elem = 2
            // and currently result = [ [],[1] ]
            var matchUps = result.Select(x => x.Concat(elem));
            //then matchUps => [ [2],[1,2] ]

             result = result.Concat(matchUps).ToList();
            //  matchUps and result concat operation
            // finally result = [ [],[1],[2],[1,2] ]
        }
        return result;
    }