【问题标题】:List of list iteration(all possible one direction combination)列表迭代列表(所有可能的单向组合)
【发布时间】:2018-09-06 15:29:08
【问题描述】:

我有一个 List<List<string>> 代表行和列的网格(每个的计数是动态的)。

我需要遍历项目并在一个方向上显示所有可能的组合。

如果我有以下物品,例如:

var items = new List<List<string>>
{
    new List<string> {"A", "B", "C", "D"},
    new List<string> {"E", "F", "G", "H"},
    new List<string> {"I", "J", "K", "L"},
};

输出应该是:

---> *ABCD-ABCH-ABCL-ABGD-ABGH-ABGL-ABKD-ABKH-ABKL-........... IJKL*.

如何遍历列表以实现此结果?

【问题讨论】:

  • 我会建议你改变你的数据结构,也许使用 graph 来促进你的搜索和优化你的性能
  • 就像你看到的here,获得所有组合并不是那么简单。当您告诉我们您为什么要实现这一目标时,也许会更容易。
  • 为什么 ABCH 在 ABCD 而不是 ABCE 之后?
  • 您能详细解释一下要求吗?考虑到所有字母,是否所有长度为 4 的组合?您的列表是否可以包含重复,如果是,它们是否算作不同的字母? “一个方向的所有可能组合”是什么意思?
  • 我注意到组合的数量增长得非常快。在这个简单的例子中,只有 81 种组合,但如果你有 3 行 10 列而不是 4 列,则几乎有 60000 种组合,而 10 行 10 列有十万亿种组合。 cmets 指出这可能是解决您的问题的糟糕技术是正确的。

标签: c# recursion iteration


【解决方案1】:

你想要的是转置的笛卡尔积。所以分解它。首先让我们进行转置:

public static List<List<T>> Transpose(
  this List<List<T>> sequences)
{
  // TODO: throw if sequences is null
  // TODO: throw if sequences contains any null
  // TODO: throw if the sequences are not all the same length
  return Enumerable.Range(0, sequences[0].Count)
    .Select(i => 
      Enumerable.Range(0, sequences.Count)
      .Select(j => sequences[j][i])
      .ToList())
    .ToList();
  }

我们可以从我的回答中获取笛卡尔积:https://stackoverflow.com/a/3098381/88656

现在你的问题的答案很简单。

IEnumerable<string> combinations = items
  .Transpose()
  .CartesianProduct()
  .Select(sequence => string.Join("", sequence));

请记住,解决这些问题的方法是将问题分解为对序列进行更基本操作的工作流,然后将扩展方法组合到工作流中 .

【讨论】:

    【解决方案2】:

    解决这个问题的另一种方法是,如果您需要 N 个唯一元素的组合,则将矩阵展平:

    var elementArray = items.SelectMany(x => x).ToList();
    

    这会将{{'A', 'B', 'C'}, {'D', 'E', 'F'}} 变成{'A', 'B', 'C', 'D', 'E', 'F'}

    然后使用取自 another question 的以下 LINQ 扩展(将其放在项目中的任何位置):

    public static class Ex
    {
        public static IEnumerable<IEnumerable<T>> DifferentCombinations<T> (this IEnumerable<T> elements, int k)
        {
            return k == 0 ? new[] { new T[0] } :
              elements.SelectMany((e, i) =>
                elements.Skip(i + 1).DifferentCombinations(k - 1).Select(c => (new[] { e }).Concat(c)));
        }
    }
    

    用作:

    var combinations = elementArray.DifferentCombinations(4)
        .Select(
            l => string.Join("", l.ToArray())
        ).ToList();
    

    在这种情况下,它的组合长度最多为 4 (DifferentCombinations(4))。

    【讨论】:

    • 此解决方案不必要地复杂且难以遵循;我不知道它是否正确。请不要只发布代码。 解释代码解决用户问题的原因。重点不仅在于解决人们的具体问题,还在于对他们进行技术教育,这样他们就不必一直回到这里来编写代码。
    • 垃圾进,垃圾出;今天有时间,我将改进我的答案。为了充分考虑未来人们试图找到这个问题,应该大力改进这个问题。
    • 现在的答案在教学法方面要好得多,但我认为它不能回答所提出的问题。我对这个问题的理解是,用户正在寻找(第 1 列中的项目)x(第 2 列中的项目)x(第 3 列中的项目)x(第 4 列中的项目)的所有组合,但看起来你只是返回所有项目的组合,而不考虑它们的列排名。
    猜你喜欢
    • 2022-12-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-12-09
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多