【问题标题】:Find all answers that are the same找出所有相同的答案
【发布时间】:2014-10-14 21:46:08
【问题描述】:

我有一份人们对问卷的回答的列表。答案目前是一个字符串数组,所以我的对象看起来像

 List<string[]> answers = new List<string[]>() 
 { new string[]{"T","A","T","F","B"},
   new string[]{"F","A","T","F","B"},
   new string[]{"T","A","F","F","B"}
 };

我需要找到所有值都相同的数组索引和值。 生成的对象可以是string[] 之类的

 {"","A","","F","B"}

或某种类型的自定义对象元组,例如 {1,"A"}, {3, "F"}, {4, "B"}

我可以假设所有字符串数组的长度都相同。

我可以通过蛮力和循环来做到这一点,但我想知道是否有更有效的清洁方式,可能通过 Linq。

这引出了一个问题,Linq 是否只是在内部使用循环,而您节省的唯一效率是代码行和必须创建局部变量。

更新: 脱离 O. R. Mapper 和 Vajura 我在想两个循环

得到第一组答案,它给出了每个字符串[] 的长度,并给出了答案应该是什么。即使第一个人是唯一回答 A 的人,那么所有其他非 A 将自动取消该索引的资格

for each index in string[]
    answer = List[0][index]
    for i=1 to List.Count - 1 
        compare answer to List[i][index]
        if false exit loop

    if we made it through it is good

【问题讨论】:

  • Linq语法糖,当编译成 IL 时会在底层使用循环等。
  • 使用 loops 并不意味着使用 brute force。而且,是的,LINQ 只是在内部使用循环,因此与正确编写的循环相比,执行效率没有固有的增益。
  • 对于这个解决方案,除了“蛮力”之外别无他法。您需要检查每个值。话虽如此,您可以对其进行很多优化,可以说第二个字符串数组的第一个索引已经不同,然后第一个索引就不再需要检查任何后续数组的值了。可能还有其他一些小事情可以优化它。
  • @Vajura 给出了两种不同的 Linq 方法,所以我不会说“蛮力”是唯一的方法。这可能是最好的方式,但肯定不是唯一的方式。

标签: c# arrays linq


【解决方案1】:

这样的事情应该可以工作:

answers
.SelectMany(x => x.Select((y, idx) => new { c = y, index = idx })) // 1
.GroupBy(x => x) // 2
.Where(x => x.Count() == answers.Count) // 3
.ToDictionary(x => x.Key.index, x => x.Key.c); // 4

这是工作的fiddle

解释是:

  1. 展平列表并选择每个字母并将其索引为匿名类型
  2. 按字母和索引对对进行分组(匿名类型根据属性值进行比较,因此我们同时按字母和索引分组)
  3. 这是棘手的部分,获取具有answer.Count 很多项目的那些组,因此我们确保字母索引对存在于所有内部数组中,换句话说:一个字母出现在所有数组中的相同索引处。
  4. 最后将组放入字典中,其中键是索引,值是字母。

【讨论】:

  • 感谢您的分解。
【解决方案2】:

好吧,只是说你可以,这里有一个Linq方法:

var results = answers.Aggregate(answers[0],(p, n) => p.Zip(n, (pi, ni) => pi==ni ? pi : "")
                                                      .ToArray())
                     .ToArray();

尽管如果您决定在实际应用中使用它,我会清楚地记录它的工作原理以及结果的含义。

实际上,这不会比设计合理的循环更有效,而且在所有其他条件相同的情况下,代码的可读性比简洁更重要。

【讨论】:

    【解决方案3】:

    LinQ 中更简单的方法:

    string[] result = answers
          .Aggregate((a, b) => 
          a.Select(a1 => (b[Array.IndexOf(a,a1)] == a1) ? a1 : "").ToArray());
    

    如果您关心性能,我建议您在数组上使用 for 循环,因为它们比在 List 上执行 foreach 快​​ 5 倍(也比 Linq 快很多)。有一些关于它的文章,但我发现this 非常有趣。另一方面,Linq 更具可读性和优雅(好吧,这只是我的看法),所以如果你的数组不太长或者你不关心性能,我推荐你这个 Linq 方法。

    【讨论】:

      猜你喜欢
      • 2013-06-13
      • 2019-09-19
      • 1970-01-01
      • 1970-01-01
      • 2011-09-15
      • 2015-07-19
      • 2020-12-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多