我有5组,每组有4个不同的数字;我想制作所有可能的组合(每个都有4个数字),这样就可以从一组中选择2个数字,而从其余组中选择其余数字(每个数字一个)。我已经在很多地方进行了搜索,并成功地编写了代码来从1组中选择组合,但很难找到上述方案的解决方案。 任何人都可以给出一些指示吗?谢谢你的帮助!
输入: -
Group 1: 1,2,3,4
Group 2: 7,8,9,10
Group 3: 15,16,17,18
Group 4: 22,23,24,25
Group 5: 27,28,29,30
预期产出: -
1,2,7,15 (2 numbers from group 1 and 1 each from group 2 and 3)
7,8,1,22 (2 numbers from group 2 and 1 each from group 1 and 4)
依旧......
以下是我的代码: -
private static bool NextCombination(IList<int> num, int n, int k)
{
bool finished;
var changed = finished = false;
if (k <= 0) return false;
for (var i = k - 1; !finished && !changed; i--)
{
if (num[i] < n - 1 - (k - 1) + i)
{
num[i]++;
if (i < k - 1)
for (var j = i + 1; j < k; j++)
num[j] = num[j - 1] + 1;
changed = true;
}
finished = i == 0;
}
return changed;
}
private static IEnumerable Combinations<T>(IEnumerable<T> elements, int k)
{
var elem = elements.ToArray();
var size = elem.Length;
if (k > size) yield break;
var numbers = new int[k];
for (var i = 0; i < k; i++)
numbers[i] = i;
do
{
yield return numbers.Select(n => elem[n]);
} while (NextCombination(numbers, size, k));
}
private static void Main()
{
const int k = 3;
var n = new[] {"1", "2", "3", "4", "5"};
Console.Write("n: " );
foreach (var item in n)
{
Console.Write("{0} ", item);
}
Console.WriteLine();
Console.WriteLine("k: {0}", k);
Console.WriteLine();
foreach (IEnumerable<string> i in Combinations(n, k))
Console.WriteLine(string.Join(" ", i));
}
}
答案 0 :(得分:2)
以下是一段代码,可以执行以下操作:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
class SelectedGroups<T>
{
public readonly IList<T> Choose2; // group to Chose 2 elements from
public readonly IList<T> Choose1_1; // first group to Chose 1 element from
public readonly IList<T> Choose1_2; // second group to Chose 1 element from
public SelectedGroups(IList<T> choose2, IList<T> choose11, IList<T> choose12)
{
Choose2 = choose2;
Choose1_1 = choose11;
Choose1_2 = choose12;
}
}
static IEnumerable<SelectedGroups<T>> ChooseGroups211<T>(IList<IList<T>> groups)
{
for (var i = 0; i < groups.Count; i++)
{
var outer = groups[i];
for (var j = 0; j < groups.Count - 1; j++)
{
if (i == j)
continue;
var first = groups[j];
// start from j+1 so k > j so groups[k] and groups[j] cover all the groups pairs excactly once
for (var k = j + 1; k < groups.Count; k++)
{
if (i == k)
continue;
yield return new SelectedGroups<T>(outer, first, groups[k]); ;
}
}
}
}
public class SelectionResult<T>
{
public readonly T Value11; // first value from the group #1
public readonly T Value12; // second value from the group #1
public readonly T Value3; // value from the group #2
public readonly T Value4; // value from the group #3
public SelectionResult(T value11, T value12, T value3, T value4)
{
Value11 = value11;
Value12 = value12;
Value3 = value3;
Value4 = value4;
}
public override string ToString()
{
return string.Format("{0} {1} {2} {3}", Value11, Value12, Value3, Value4);
}
}
static IEnumerable<SelectionResult<T>> Select211FromGroups<T>(SelectedGroups<T> groups)
{
for (var i = 0; i < groups.Choose2.Count - 1; i++)
{
var value11 = groups.Choose2[i];
// start from i+1 so j > i so groups.Choose2[i] and groups.Choose2[j] cover all the pairs excactly once
for (var j = i + 1; j < groups.Choose2.Count; j++)
{
var value12 = groups.Choose2[j];
foreach (var value3 in groups.Choose1_1)
{
foreach (var value4 in groups.Choose1_2)
{
yield return new SelectionResult<T>(value11, value12, value3, value4);
}
}
}
}
}
public static IEnumerable<SelectionResult<T>> Select211<T>(IList<IList<T>> groups)
{
return ChooseGroups211(groups).SelectMany(g => Select211FromGroups(g));
}
public static void Main(string[] args)
{
//PrintHex(4);
List<int> g1 = new List<int>() { 1, 2, 3, 4 };
List<int> g2 = new List<int>() { 7, 8, 9, 10 };
List<int> g3 = new List<int>() { 15, 16, 17, 18 };
List<int> g4 = new List<int>() { 22, 23, 24, 25 };
List<int> g5 = new List<int>() { 27, 28, 29, 30 };
var allGroups = new List<IList<int>>() { g1, g2, g3, g4, g5 };
foreach (var selectionResult in Select211(allGroups))
{
Console.WriteLine(selectionResult);
}
}
}
请参阅online demo。
代码背后的想法如下:
首先从所有组3中选择以从中选择元素。即生成所有此类IEnumerable
的{{1}}。这是通过方法SelectedGroups
完成的。这里重点是ChooseGroups211
和Choose1_1
是完全对称的,因此您只想选择两对Choose1_2
和(Gi, Gj)
。
从每个固定(Gj, Gi)
生成4个元素(SelectedGroups
)的所有组合。这是通过方法SelectionResult<T>
完成的。同样Select211FromGroups
和Value11
是对称的,因此您只想选择两对中的一对。
使用SelectMany
将这些构建基块加入到您想要的方法中,Value12
。
注意:这段代码非常简单,但同时它对于这个特定的任务来说几乎是硬编码的,即选择恰好4个元素为2 + 1 + 1.这允许我使用命名类型而不是Select211
的结果和中间结果,我通常更喜欢。如果要求不同,我可能会使用通用的IEnumerable<T>
或数组IEnumerable
以及一些更高级的技巧,例如Computing a Cartesian product with LINQ