LINQ:选择列表中仅出现一次的元素

7

我有一个对象列表,类型可以是任何类型T

如何使用Linq选择仅在该列表中出现一次的对象列表?例如,如果我的列表是{2,3,4,5,8,2,3,5,4,2,3,4,6},则输出应为{6,8}

3个回答

7
你可以尝试这个方法:
int[] arr = { 2, 3, 4, 5, 8, 2, 3, 5, 4, 2, 3, 4, 6 };
var q =
    from g in arr.GroupBy(x => x)
    where g.Count() == 1
    select g.First();

你需要为泛型 T 编写一个测试相等性的方法。不过这是非常好的答案。 - Nick Larsen
@NickLarsen你能举个例子吗?很有趣。 - nawfal
@nawfal 这是几年前的事了,我不记得当时在做什么了,抱歉。 - Nick Larsen

3
使用 Count() 函数。
    int[] a = {2,3,4,5,8,2,3,5,4,2,3,4,6};

    var selection = from i in a
        where (a.Count(n => n == i) == 1)
        select i;

1
注意:这不是一个新答案,只是对其他答案的详细说明。
虽然OP明确要求使用Linq来回答问题,但我认为值得一提的是,有时使用Linq也有缺点。它可以编写简洁且(大多数情况下)易读的代码,但并不总是生成最有效的底层代码(例如,在给定的其他答案中,每次调用Count方法都会枚举整个数组)。
因此,有时候传统的过程式代码是更好的选择。
为了说明这一点,我编写了两个替代实现:一个使用字典,另一个使用两个哈希集。这两种方法只枚举一次数组。
基准测试结果:
方法 数组 平均时间(ns) 相对值 误差 标准偏差 Gen0 Gen1 分配内存 相对值
使用Linq获取唯一值 Int32[10000] 330,502.4ns 100% 3,771.44ns 3,527.81ns 62.5000 18.5547 294616 B 100%
使用Dictionary获取唯一值 Int32[10000] 161,602.2ns 49% 873.37ns 774.22ns 15.3809 2.4414 73336 B 25%
使用HashSet获取唯一值 Int32[10000] 120,871.6ns 37% 412.96ns 366.07ns 15.1367 2.0752 71616 B 24%
使用Linq获取唯一值 Int32[1000] 63,855.5ns 100% 813.66ns 679.45ns 18.6768 3.6621 88104 B 100%
使用Dictionary获取唯一值 Int32[1000] 27,243.4ns 42% 184.51ns 172.59ns 8.1787 0.0916 38600 B 44%
使用HashSet获取唯一值 Int32[1000] 22,269.1ns 35% 232.72ns 217.68ns 5.8289 0.2747 27440 B [MemoryDiagnoser] public class UniqueSelector { public IEnumerable<int[]> Data() { var rnd = new Random(1); yield return new int[] { 2, 3, 4, 5, 8, 2, 3, 5, 4, 2, 3, 4, 6 }; yield return Enumerable.Range(0, 1000).Select(i => rnd.Next(1000)).ToArray(); yield return Enumerable.Range(0, 10000).Select(i => rnd.Next(1000)).ToArray(); } [Benchmark] [ArgumentsSource(nameof(Data))] public int[] GetUniquesByLinq(int[] array) { var q = from g in array.GroupBy(x => x) where g.Count() == 1 select g.First(); return q.ToArray(); } [Benchmark] [ArgumentsSource(nameof(Data))] public int[] GetUniquesByDictionary(int[] array) { var counts = new Dictionary<int, int>(); foreach (int item in array) { if (!counts.TryAdd(item, 1)) counts[item]++; } return counts.Where(kv => kv.Value == 1).Select(kv => kv.Key).ToArray(); } [Benchmark] [ArgumentsSource(nameof(Data))] public int[] GetUniquesByHashSet(int[] array) { var uniques = new HashSet<int>(); var duplicates = new HashSet<int>(); foreach (int item in array) { if (duplicates.Contains(item)) continue; if (uniques.Contains(item)) { duplicates.Add(item); uniques.Remove(item); continue; } uniques.Add(item); } return uniques.ToArray(); } }

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接