C# 为2个集合中的实体生成所有可能性

C# 为2个集合中的实体生成所有可能性,c#,algorithm,C#,Algorithm,我将我的盲点简化为以下几点 假设您有4个实体a、b、c和d;2个集合x和y;可能是因为 (x;y) => (abcd;)(abc;d)(abd;c)(acd;b)(bcd;a)(ac;bd)(ad;bc)(ab;dc)(bc;ad)etc.. 简而言之,我需要以一种有效的方式为m个集合中的n个实体生成所有可能的结果 (关于域的更多信息,我不关心排序,因此(ab;cd)在我的案例中基本上与(ba;cd)相同,如果这将使您更容易理解的话)给出了一个非常密切相关的答案,它涉及所有子集的生成。给

我将我的盲点简化为以下几点

假设您有4个实体a、b、c和d;2个集合x和y;可能是因为

(x;y) => (abcd;)(abc;d)(abd;c)(acd;b)(bcd;a)(ac;bd)(ad;bc)(ab;dc)(bc;ad)etc..
简而言之,我需要以一种有效的方式为m个集合中的n个实体生成所有可能的结果


(关于域的更多信息,我不关心排序,因此(ab;cd)在我的案例中基本上与(ba;cd)相同,如果这将使您更容易理解的话)

给出了一个非常密切相关的答案,它涉及所有子集的生成。给定序列的所有子集都可以由下面的代码段生成,该代码段取自此处

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);
}
}
基于所有子集的枚举,可以通过确定补码来计算所需的解,如下所示

public class Partition
{
    public IEnumerable<string> First;
    public IEnemurable<string> Second;
};

var input = new string[]{ "a", "b", "c", "d" };
var subsets = Getsubsets(input);
var Partitions = new List<Partition>();
foreach (var subset in subsets)
{
    var iPart = new Partition();
    iPart.First = subset;
    iPart.Second = input.Where(iEl => false == subset.Contains(iEl));
    Partitions.Add(iPart);
}
公共类分区
{
公共数字优先;
第二,公众参与;
};
变量输入=新字符串[]{“a”、“b”、“c”、“d”};
var子集=Getsubsets(输入);
var Partitions=newlist();
foreach(子集中的var子集)
{
var iPart=新分区();
iPart.First=子集;
iPart.Second=input.Where(iEl=>false==subset.Contains(iEl));
分区。添加(iPart);
}

这里是一个使用状态a而不是
bool[]
位数组的实现:

using System.Numerics;

public static IEnumerable<(T[], T[])> GetCollectionPairs<T>(T[] source)
{
    BigInteger combinations = BigInteger.One << source.Length;
    for (BigInteger i = 0; i < combinations; i++)
    {
        yield return
        (
            Enumerable.Range(0, source.Length)
            .Where(j => (i & (BigInteger.One << j)) != 0)
            .Select(j => source[j])
            .ToArray(),
            Enumerable.Range(0, source.Length)
            .Where(j => (i & (BigInteger.One << j)) == 0)
            .Select(j => source[j])
            .ToArray()
        );
    }
}
输出:

(;ABCD)
(b;BCD)
(B;ACD)
(AB;CD)
(C;ABD)
(AC;BD)
(公元前;公元前)
(ABC;D)
(D;ABC)
(公元前)公元前
(BD;AC)
(ABD;C)
(CD;AB)
(ACD;B)
(BCD;A)
(ABCD;)

这将生成(AB;CD)和(CD;AB)作为不同的对。如果不需要这样做,则只需循环直到
i
而不是
i

var items = new string[] { "A", "B", "C", "D" };
var pairs = GetCollectionPairs(items);
foreach (var pair in pairs)
{
    Console.WriteLine(
        $"({String.Join("", pair.Item1)};{String.Join("", pair.Item2)})");
}