C# 找到所有相同的答案
我有一份人们对调查问卷的答案清单。答案当前是一个字符串数组,因此我的对象看起来像C# 找到所有相同的答案,c#,arrays,linq,C#,Arrays,Linq,我有一份人们对调查问卷的答案清单。答案当前是一个字符串数组,因此我的对象看起来像 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"} }; 或者某种类型的自定义对象元组,类似于{1,“A”},{3,“F
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"}
};
或者某种类型的自定义对象元组,类似于{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
像这样的方法应该会奏效:
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
这是工作票
解释如下:
答案的组。计算许多项,因此我们确保字母索引对存在于所有内部数组中,换句话说:所有数组中的同一索引处都存在一个字母
像这样的方法应该会奏效:
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
这是工作票
解释如下:
答案的组。计算许多项,因此我们确保字母索引对存在于所有内部数组中,换句话说:所有数组中的同一索引处都存在一个字母
var results = answers.Aggregate(answers[0],(p, n) => p.Zip(n, (pi, ni) => pi==ni ? pi : "")
.ToArray())
.ToArray();
虽然如果你决定在一个真正的应用程序中使用它,我会清楚地记录它是如何工作的以及结果意味着什么
实际上,这并不比一个设计合理的循环更有效,代码可读性比简洁性更重要,在所有其他条件相同的情况下。好吧,只是说你可以,这里有一个Linq方法:
var results = answers.Aggregate(answers[0],(p, n) => p.Zip(n, (pi, ni) => pi==ni ? pi : "")
.ToArray())
.ToArray();
虽然如果你决定在一个真正的应用程序中使用它,我会清楚地记录它是如何工作的以及结果意味着什么
实际上,这并不比一个设计合理的循环更有效,代码可读性比简洁性更重要,在其他条件相同的情况下。LinQ中更简单的方法是:
string[] result = answers
.Aggregate((a, b) =>
a.Select(a1 => (b[Array.IndexOf(a,a1)] == a1) ? a1 : "").ToArray());
如果您关心性能,我建议您对数组上的循环使用
,因为它们比在列表上执行
foreach快5倍(也比Linq快得多)。有一些关于它的文章,但我觉得很有趣。另一方面,Linq更具可读性和优雅性(好吧,这只是我的观点),因此如果您的阵列不太长或者您不关心性能,我建议您使用这种Linq方法。Linq中一种更简单的方法:
string[] result = answers
.Aggregate((a, b) =>
a.Select(a1 => (b[Array.IndexOf(a,a1)] == a1) ? a1 : "").ToArray());
如果您关心性能,我建议您对数组上的循环使用
,因为它们比在列表上执行
foreach快5倍(也比Linq快得多)。有一些关于它的文章,但我觉得很有趣。另一方面,Linq更具可读性和优雅性(好吧,这只是我的观点),因此,如果您的数组不是太长或者您不关心性能,我建议您使用这种Linq方法。Linq是一种语法糖,编译为IL时将在后台使用循环等。使用循环并不意味着使用暴力。而且,是的,LINQ只是在内部使用循环,因此与正确编写的循环相比,执行效率没有内在的提高。对于这个解决方案,除了“暴力”之外,没有其他方法。您需要检查每个值。也就是说,您可以对其进行大量优化,假设第二个字符串数组的第一个索引已经与第一个索引不同,那么您不需要再为任何后续数组检查该值。可能还有其他一些小事情可以优化它。@Vajura已经给出了两种不同的Linq方法,所以我不会说“暴力”是唯一的方法。这可能是最好的方法,但肯定不是唯一的方法。Linq是语法糖,当编译成IL时,将在后台使用循环等。使用循环并不意味着使用暴力。而且,是的,LINQ只是在内部使用循环,因此与正确编写的循环相比,执行效率没有内在的提高。对于这个解决方案,除了“暴力”之外,没有其他方法。您需要检查每个值。也就是说,您可以对其进行大量优化,假设第二个字符串数组的第一个索引已经与第一个索引不同,那么您不需要再为任何后续数组检查该值。可能还有其他一些小事情可以优化它。@Vajura已经给出了两种不同的Linq方法,所以我不会说“暴力”是唯一的方法。这可能是最好的方法,但肯定不是唯一的方法。谢谢你的失败。谢谢你的失败。