C# c与linq的组合

C# c与linq的组合,c#,linq,combinations,C#,Linq,Combinations,我有一个值数组,例如{0,1,2},它可以处于两种状态{0,1}中的一种 是否有一种简单的方法可以使用linq查询获得{value,state}的所有组合的列表,其中value是唯一的,这样我可以得到如下结果: { { { 0, 0 }, { 1, 0 }, { 2, 0 } }, { { 0, 0 }, { 1, 0 }, { 2, 1 } }, { { 0, 0 }, { 1, 1 }, { 2, 0 } }, { { 0, 0 }, { 1, 1 }, { 2, 1 } }, { { 0,

我有一个值数组,例如{0,1,2},它可以处于两种状态{0,1}中的一种

是否有一种简单的方法可以使用linq查询获得{value,state}的所有组合的列表,其中value是唯一的,这样我可以得到如下结果:

{
{ { 0, 0 }, { 1, 0 }, { 2, 0 } },
{ { 0, 0 }, { 1, 0 }, { 2, 1 } },
{ { 0, 0 }, { 1, 1 }, { 2, 0 } },
{ { 0, 0 }, { 1, 1 }, { 2, 1 } },
{ { 0, 1 }, { 1, 0 }, { 2, 0 } },
{ { 0, 1 }, { 1, 0 }, { 2, 1 } },
{ { 0, 1 }, { 1, 1 }, { 2, 0 } },
{ { 0, 1 }, { 1, 1 }, { 2, 1 } },
}
值数组的大小可以不同,但它们只能处于两种状态之一

确切地说,这不是笛卡尔的产品,我不确定用什么术语来描述它,所以不知道谷歌应该做什么

谢谢

试试看

var values = new int[]{0,1,2};
var states = new int[]{0,1};

var permutations = from v in values
                   from s in states
                   select new {v,s}
您只需要两个数组的叉积,而不考虑数组的大小

var values = new int[]{0,1,2};
var states = new int[]{0,1};

var permutations = from v in values
                   from s in states
                   select new {v,s}

您只需要两个数组的叉积,而不考虑数组的大小

它是笛卡尔积的笛卡尔积:

var groups = from x in 
                (from v in values
                 from s in states
                 select new {v,s})
             group x by x.v into gx
             select gx;

var perms = from a in groups[0]
            from b in groups[1]
            from c in groups[2]
            select new {a,b,c}; 
groups查询在概念上生成一个查找,即IEnumerables的只读字典,其中包含所有值和状态6个元素的简单笛卡尔乘积,并按它们的值分组。然后,第二个查询生成笛卡尔乘积,笛卡尔乘积的元素一次取三个,在查找中每组取一个

要在未知数量的维度上实现这一点是很困难的;如果你不一定要这样做,我会避免的。我认为最优雅的方法是为系统定义一组扩展方法。元组泛型类:

public static Tuple<T1,T2> Append(this Tuple<T1> tuple, T2 addend)
{
   return Tuple.Create(tuple.Item1, addend);
}

public static Tuple<T1,T2, T3> Append(this Tuple<T1,T2> tuple, T3 addend)
{
   return Tuple.Create(tuple.Item1, tuple.Item2, addend);
}

...
然后,您可以获取这些帮助程序并在第二个查询的循环版本中使用它们:

var perms=来自组[0]中的a 选择Tuple.Createa

组中的foreachvar组。Skip1 烫发=从烫发中的a开始 来自b组 选择a.附录b


这将生成所需长度的元组枚举,其中包含在第一个查询中生成的匿名类型的元素,如果您愿意,可以重构这些元素以生成强类型的2项元组。使用perms collection变量引用不断增长的元组集合可能会有问题;这是一个棘手的部分。

这是笛卡尔积的笛卡尔积:

var groups = from x in 
                (from v in values
                 from s in states
                 select new {v,s})
             group x by x.v into gx
             select gx;

var perms = from a in groups[0]
            from b in groups[1]
            from c in groups[2]
            select new {a,b,c}; 
groups查询在概念上生成一个查找,即IEnumerables的只读字典,其中包含所有值和状态6个元素的简单笛卡尔乘积,并按它们的值分组。然后,第二个查询生成笛卡尔乘积,笛卡尔乘积的元素一次取三个,在查找中每组取一个

要在未知数量的维度上实现这一点是很困难的;如果你不一定要这样做,我会避免的。我认为最优雅的方法是为系统定义一组扩展方法。元组泛型类:

public static Tuple<T1,T2> Append(this Tuple<T1> tuple, T2 addend)
{
   return Tuple.Create(tuple.Item1, addend);
}

public static Tuple<T1,T2, T3> Append(this Tuple<T1,T2> tuple, T3 addend)
{
   return Tuple.Create(tuple.Item1, tuple.Item2, addend);
}

...
然后,您可以获取这些帮助程序并在第二个查询的循环版本中使用它们:

var perms=来自组[0]中的a 选择Tuple.Createa

组中的foreachvar组。Skip1 烫发=从烫发中的a开始 来自b组 选择a.附录b

这将生成所需长度的元组枚举,其中包含在第一个查询中生成的匿名类型的元素,如果您愿意,可以重构这些元素以生成强类型的2项元组。使用perms collection变量引用不断增长的元组集合可能会有问题;这是棘手的部分。

可能类似于:

var lst1 = new List<int> { 0, 1, 2 };
var lst2 = new List<int> { 0, 1 };

lst1.ForEach(i => {
    Console.WriteLine("{");
    lst2.ForEach(j => Console.Write("{ " + i + "," + j + "}"));
    Console.WriteLine("}");
});
这不是你想要的格式;您应该构建某种数组,然后将其连接到上,和/或},{。不过,这应该会给您一个大致的想法。

可能类似于:

var lst1 = new List<int> { 0, 1, 2 };
var lst2 = new List<int> { 0, 1 };

lst1.ForEach(i => {
    Console.WriteLine("{");
    lst2.ForEach(j => Console.Write("{ " + i + "," + j + "}"));
    Console.WriteLine("}");
});

这并不是您想要的格式;您应该构建某种数组,然后将其连接起来,和/或},{。这应该给您一个大致的想法。

由于这两种状态可以被视为位,您可以通过简单地计算位并将其转换为数组中的项来获得组合:

int maxValue = 2;
int[][][] values = Enumerable.Range(0, 1 << maxValue).Select(n =>
  Enumerable.Range(0, maxValue + 1).Select(m =>
    new[] { m, (n >> (maxValue - m)) & 1 }
  ).ToArray()
).ToArray();

由于这两种状态可视为位,您可以通过简单地计算并将位转换为数组中的项来获得组合:

int maxValue = 2;
int[][][] values = Enumerable.Range(0, 1 << maxValue).Select(n =>
  Enumerable.Range(0, maxValue + 1).Select(m =>
    new[] { m, (n >> (maxValue - m)) & 1 }
  ).ToArray()
).ToArray();

那不是排列,那是组合。例如,排列将把123变成{123132213231312321}。这不是偶数组合。这是一个伪装的笛卡尔积:-。好吧,我把排列改成了组合。那不是排列,那是组合。例如,排列将把123变成{123,132,213,231,312,321}。它甚至不是组合。它是一个伪装的笛卡尔积:-。好吧,反正我把排列改为组合。不,要求的不是叉积。你的代码将产生6对,而需要的是8对三元组。不,要求的不是叉积。你的代码将产生6对,而需要的是是8个三元组对。这个答案让我有些困惑。我认为它应该是groups查询中的groups x by?gx是如何到达第二个查询的?您使用索引0 1 2这一事实明确地让我认为这不会处理变化的值arra
y码?对不起,我是linq的新手,所以可能遗漏了一些显而易见的东西;我更新了GROUPBY子句和对分组数据的引用。用未知数量的维度来完成这项工作将是棘手的,但也是可能的;基本上,您将循环执行一个查询,该查询获取上一个查询的结果,笛卡尔将下一个维度加入到每个结果中。诀窍是将该结构从这些嵌套数组或匿名类型展平到元组的一维集合中。谢谢您的编辑。为了能够索引groups变量,我不得不使用.ToArray。我将尝试改变维度,看看我能想出什么。编写查询的技巧更容易阅读:子查询尾中的from x也可以将子查询写入x尾。因此,您的查询可以是从v中的值,从s中的状态选择新的{v,s}到x组x,再从x.v到gx选择gx。这种语法的好处是更容易从上到下阅读;您不会引入一个直到很久以后才使用的范围变量x。这个查询延续语法使范围变量的引入更接近它们的用法。创建查找组后,我可以调用'var cornerCoords=CartesianProductgroups.ToArray;'我对这个答案有点困惑。我想它应该是groups查询中的groupx by?gx如何进入第二个查询?您显式地使用索引0 1 2这一事实让我认为这不会处理数组大小不同的值?对不起,我是linq的新手,所以可能遗漏了一些显而易见的东西;我更新了GROUPBY子句和对分组数据的引用。用未知数量的维度来完成这项工作将是棘手的,但也是可能的;基本上,您将循环执行一个查询,该查询获取上一个查询的结果,笛卡尔将下一个维度加入到每个结果中。诀窍是将该结构从这些嵌套数组或匿名类型展平到元组的一维集合中。谢谢您的编辑。为了能够索引groups变量,我不得不使用.ToArray。我将尝试改变维度,看看我能想出什么。编写查询的技巧更容易阅读:子查询尾中的from x也可以将子查询写入x尾。因此,您的查询可以是从v中的值,从s中的状态选择新的{v,s}到x组x,再从x.v到gx选择gx。这种语法的好处是更容易从上到下阅读;您不会引入一个直到很久以后才使用的范围变量x。这个查询延续语法使范围变量的引入更接近它们的用法。创建查找组后,我可以调用'var cornerCoords=CartesianProductgroups.ToArray;'