使用LINQ,从一个列表<int>,我怎么能检索一个列表,包含重复不止一次的条目和他们的值?


当前回答

只查找重复的值:

var duplicates = list.GroupBy(x => x.Key).Where(g => g.Count() > 1);

E.g.

var list = new[] {1,2,3,1,4,2};

GroupBy将根据它们的键对数字进行分组,并使用它维护计数(重复的次数)。在那之后,我们只是检查重复了不止一次的值。

要查找唯一的值:

var unique = list.GroupBy(x => x.Key).Where(g => g.Count() == 1);

E.g.

var list = new[] {1,2,3,1,4,2};

GroupBy将根据它们的键对数字进行分组,并使用它维护计数(重复的次数)。在此之后,我们只是检查那些只重复一次的值是否惟一。

其他回答

你可以这样做:

var list = new[] {1,2,3,1,4,2};
var duplicateItems = list.Duplicates();

使用这些扩展方法:

public static class Extensions
{
    public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
    {
        var grouped = source.GroupBy(selector);
        var moreThan1 = grouped.Where(i => i.IsMultiple());
        return moreThan1.SelectMany(i => i);
    }

    public static IEnumerable<TSource> Duplicates<TSource, TKey>(this IEnumerable<TSource> source)
    {
        return source.Duplicates(i => i);
    }

    public static bool IsMultiple<T>(this IEnumerable<T> source)
    {
        var enumerator = source.GetEnumerator();
        return enumerator.MoveNext() && enumerator.MoveNext();
    }
}

在duplicate方法中使用IsMultiple()比Count()更快,因为这不会迭代整个集合。

找出一个枚举对象是否包含任何重复项:

var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);

找出一个枚举对象中的所有值是否都是唯一的:

var allUnique = enumerable.GroupBy(x => x.Key).All(g => g.Count() == 1);

有一个答案,但我不明白为什么不工作;

var anyDuplicate = enumerable.GroupBy(x => x.Key).Any(g => g.Count() > 1);

我的解是这样的;

var duplicates = model.list
                    .GroupBy(s => s.SAME_ID)
                    .Where(g => g.Count() > 1).Count() > 0;
if(duplicates) {
    doSomething();
}

完整的集Linq到SQL扩展的重复功能检查在MS SQL Server。不使用. tolist()或IEnumerable。这些查询在SQL Server中执行,而不是在内存中。结果只在内存中返回。

public static class Linq2SqlExtensions {

    public class CountOfT<T> {
        public T Key { get; set; }
        public int Count { get; set; }
    }

    public static IQueryable<TKey> Duplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => s.Key);

    public static IQueryable<TSource> GetDuplicates<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).SelectMany(s => s);

    public static IQueryable<CountOfT<TKey>> DuplicatesCounts<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(y => new CountOfT<TKey> { Key = y.Key, Count = y.Count() });

    public static IQueryable<Tuple<TKey, int>> DuplicatesCountsAsTuble<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> groupBy)
        => source.GroupBy(groupBy).Where(w => w.Count() > 1).Select(s => Tuple.Create(s.Key, s.Count()));
}

所有的GroupBy答案都是最简单的,但不是最有效的。它们对内存性能尤其不利,因为构建大型内部集合需要分配成本。

一个不错的替代方案是HuBeZa的HashSet。基于添加的方法。它表现得更好。

如果你不关心空值,就我所知,像这样的东西是最有效的(CPU和内存):

public static IEnumerable<TProperty> Duplicates<TSource, TProperty>(
    this IEnumerable<TSource> source,
    Func<TSource, TProperty> duplicateSelector,
    IEqualityComparer<TProperty> comparer = null)
{
    comparer ??= EqualityComparer<TProperty>.Default;

    Dictionary<TProperty, int> counts = new Dictionary<TProperty, int>(comparer);

    foreach (var item in source)
    {
        TProperty property = duplicateSelector(item);
        counts.TryGetValue(property, out int count);

        switch (count)
        {
            case 0:
                counts[property] = ++count;
                break;

            case 1:
                counts[property] = ++count;
                yield return property;
                break;
        }
    }
}

这里的技巧是在重复数达到1时避免额外的查找成本。当然,如果您还想知道每个项重复出现的次数,则可以使用count不断更新字典。对于null,你只需要一些额外的处理,仅此而已。