【问题标题】:Every combination of "1 item from each of N collections"“N 个集合中的每个集合中的 1 个项目”的每个组合
【发布时间】:2016-06-02 12:44:53
【问题描述】:

我有一个嵌套的List<List<int>> 数据结构,我想遍历最里面的int 元素的每个可能组合,例如在每个组合中,每个内部List<int> 中的一个值被使用。例如,请考虑以下嵌套列表:

var listOfLists = new List<List<int>>()
{
    new List<int>() { 1, 2, 3, 4, 9 },
    new List<int>() { 0, 3, 4, 5 },
    new List<int>() { 1, 6 }
};

前几个组合会产生:

1 0 1 // Indices: 0 0 0
1 0 6 // Indices: 0 0 1
1 3 1 // Indices: 0 1 0
1 3 6 // Indices: 0 1 1
2 0 1 // Indices: 1 0 0
2 0 6 // Indices: 1 0 1
2 3 1 // Indices: 1 1 0
...

我怎样才能做到这一点?

我最初的方法是对索引进行排列,但内部 List&lt;int&gt; 列表的长度不一定相等。我能想到的另一种方法是将每个内部 List&lt;int&gt; 的长度相乘,然后使用模数和除法运算符结合 Math.Floor 来确定索引,但我不确定当 N 集合时如何实现存在。

【问题讨论】:

标签: c# arrays


【解决方案1】:

我已经回答了几个类似的问题,它们基本上都使用同一种算法的变体。这是Looking at each combination in jagged array的修改版:

public static class Algorithms
{
    public static IEnumerable<T[]> GetCombinations<T>(this IReadOnlyList<IReadOnlyList<T>> input)
    {
        var result = new T[input.Count];
        var indices = new int[result.Length];
        for (int pos = 0, index = 0; ;)
        {
            for (; pos < result.Length; pos++, index = 0)
            {
                indices[pos] = index;
                result[pos] = input[pos][index];
            }
            yield return result;
            do
            {
                if (pos == 0) yield break;
                index = indices[--pos] + 1;
            }
            while (index >= input[pos].Count);
        }
    }
}

请注意,为了不进行分配,上述方法会产生一个相同的数组实例。如果您只想使用 foreach 循环或 LINQ 查询来计算或处理它而不存储结果,这是完美的选择。例如:

foreach (var combination in listOfLists.GetCombinations())
{
    // do something with the combination
}

如果确实需要存储结果,可以随时使用ToList

var allCombinations = listOfLists.GetCombinations().Select(c => c.ToList()).ToList();

【讨论】:

  • 从性能的角度来看,这似乎非常有效。我仍在努力理解这个 sn-p 的每个部分,但我是否正确地假设每个结果组合中的元素顺序总是反映传入的列表的顺序?
  • 正确。怎么理解,基本上算法是嵌套for/foreach循环的展开版本:)。
【解决方案2】:

使用 LINQ 怎么样?

var listOfLists = new List<List<int>>()
{
    new List<int>() { 1, 2, 3, 4, 9 },
    new List<int>() { 0, 3, 4, 5 },
    new List<int>() { 1, 6 }
};

var result = from l in listOfLists[0]
             from y in listOfLists[1]
             from z in listOfLists[2]
             select new List<int>()
             {
                 l,
                 y,
                 z
             };

这当然只适用于这个特定的列表,因为您的列表中有 3 个列表。

【讨论】:

  • “这当然只适用于这个特定的列表” -- 这是我的问题,List&lt;List&lt;int&gt;&gt; 中可以有任意数量的 List&lt;int&gt; 元素价值。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2013-07-13
  • 1970-01-01
  • 1970-01-01
  • 2018-12-10
  • 1970-01-01
  • 1970-01-01
  • 2011-12-03
相关资源
最近更新 更多