Как получить дубликаты элементов из списка с помощью LINQ?

У меня есть List<string> как:

List<String> list = new List<String>{"6","1","2","4","6","5","1"};

Мне нужно получить дубликаты элементов в списке в новый список. Теперь я использую вложенный цикл for, чтобы сделать это.

В результате list будет содержать {"6","1"}.

Есть ли идея сделать это, используя LINQ или лямбда-выражения?

Ответ 1

var duplicates = lst.GroupBy(s => s)
    .SelectMany(grp => grp.Skip(1));

Обратите внимание, что при этом будут возвращены все дубликаты, поэтому, если вы хотите узнать только, какие элементы дублируются в исходном списке, вы можете применить Distinct к полученной последовательности или использовать решение, данное Марком Байерсом.

Ответ 2

Вот один из способов сделать это:

List<String> duplicates = lst.GroupBy(x => x)
                             .Where(g => g.Count() > 1)
                             .Select(g => g.Key)
                             .ToList();

GroupBy группирует элементы, которые являются одинаковыми вместе, а Where отфильтровывает те, которые появляются только один раз, оставляя только дубликаты.

Ответ 3

Вот еще один вариант:

var list = new List<string> { "6", "1", "2", "4", "6", "5", "1" };

var set = new HashSet<string>();
var duplicates = list.Where(x => !set.Add(x));

Ответ 4

Я знаю, что это не ответ на исходный вопрос, но вы можете оказаться здесь с этой проблемой.

Если вы хотите, чтобы все повторяющиеся элементы в ваших результатах работали, выполните следующие действия.

var duplicates = list
    .GroupBy( x => x )               // group matching items
    .Where( g => g.Skip(1).Any() )   // where the group contains more than one item
    .SelectMany( g => g );           // re-expand the groups with more than one item

В моей ситуации мне нужны все дубликаты, чтобы я мог отметить их в пользовательском интерфейсе как ошибки.

Ответ 5

Я написал этот метод расширения, основанный на ответе @Lee на OP. Обратите внимание, что использовался параметр по умолчанию (требуется С# 4.0). Тем не менее, перегруженный вызов метода в С# 3.0 был бы достаточным.

/// <summary>
/// Method that returns all the duplicates (distinct) in the collection.
/// </summary>
/// <typeparam name="T">The type of the collection.</typeparam>
/// <param name="source">The source collection to detect for duplicates</param>
/// <param name="distinct">Specify <b>true</b> to only return distinct elements.</param>
/// <returns>A distinct list of duplicates found in the source collection.</returns>
/// <remarks>This is an extension method to IEnumerable&lt;T&gt;</remarks>
public static IEnumerable<T> Duplicates<T>
         (this IEnumerable<T> source, bool distinct = true)
{
     if (source == null)
     {
        throw new ArgumentNullException("source");
     }

     // select the elements that are repeated
     IEnumerable<T> result = source.GroupBy(a => a).SelectMany(a => a.Skip(1));

     // distinct?
     if (distinct == true)
     {
        // deferred execution helps us here
        result = result.Distinct();
     }

     return result;
}

Ответ 6

Надеюсь, что эта помощь поможет

int[] listOfItems = new[] { 4, 2, 3, 1, 6, 4, 3 };

var duplicates = listOfItems 
    .GroupBy(i => i)
    .Where(g => g.Count() > 1)
    .Select(g => g.Key);

foreach (var d in duplicates)
    Console.WriteLine(d);

Ответ 7

  List<String> list = new List<String> { "6", "1", "2", "4", "6", "5", "1" };

    var q = from s in list
            group s by s into g
            where g.Count() > 1
            select g.First();

    foreach (var item in q)
    {
        Console.WriteLine(item);

    }

Ответ 8

Я пытался решить то же самое со списком объектов и имел проблемы, потому что пытался переупаковать список групп в исходный список. Поэтому я придумал цикл по группам, чтобы переупаковать исходный список с элементами, имеющими дубликаты.

public List<MediaFileInfo> GetDuplicatePictures()
{
    List<MediaFileInfo> dupes = new List<MediaFileInfo>();
    var grpDupes = from f in _fileRepo
                   group f by f.Length into grps
                   where grps.Count() >1
                   select grps;
    foreach (var item in grpDupes)
    {
        foreach (var thing in item)
        {
            dupes.Add(thing);
        }
    }
    return dupes;
}

Ответ 9

Все упомянутые решения до сих пор выполняют GroupBy. Даже если мне нужен только первый Дубликат, все элементы коллекций перечисляются хотя бы один раз.

Следующая функция расширения перестает перечисляться, как только будет найден дубликат. Он продолжается, если запрашивается следующий дубликат.

Как всегда в LINQ есть две версии: одна с IEqualityComparer и одна без нее.

public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource> source)
{
    return source.ExtractDuplicates(null);
}
public static IEnumerable<TSource> ExtractDuplicates(this IEnumerable<TSource source,
    IEqualityComparer<TSource> comparer);
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    if (comparer == null)
        comparer = EqualityCompare<TSource>.Default;

    HashSet<TSource> foundElements = new HashSet<TSource>(comparer);
    foreach (TSource sourceItem in source)
    {
        if (!foundElements.Contains(sourceItem))
        {   // we've not seen this sourceItem before. Add to the foundElements
            foundElements.Add(sourceItem);
        }
        else
        {   // we've seen this item before. It is a duplicate!
            yield return sourceItem;
        }
    }
}

Использование:

IEnumerable<MyClass> myObjects = ...

// check if has duplicates:
bool hasDuplicates = myObjects.ExtractDuplicates().Any();

// or find the first three duplicates:
IEnumerable<MyClass> first3Duplicates = myObjects.ExtractDuplicates().Take(3)

// or find the first 5 duplicates that have a Name = "MyName"
IEnumerable<MyClass> myNameDuplicates = myObjects.ExtractDuplicates()
    .Where(duplicate => duplicate.Name == "MyName")
    .Take(5);

Для всех этих операторов linq коллекция обрабатывается только до тех пор, пока не будут найдены запрошенные элементы. Остальная последовательность не интерпретируется.

IMHO - это повышение эффективности.