C # LINQ는 목록에서 중복을 찾습니다.


답변:


567

문제를 해결하는 가장 쉬운 방법은 값을 기준으로 요소를 그룹화 한 다음 그룹에 둘 이상의 요소가있는 경우 그룹의 대표자를 선택하는 것입니다. LINQ에서는 다음과 같이 해석됩니다.

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .Select(y => y.Key)
              .ToList();

요소가 몇 번 반복되는지 알고 싶다면 다음을 사용할 수 있습니다.

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .Select(y => new { Element = y.Key, Counter = y.Count() })
              .ToList();

List익명 형식 을 반환 하고 각 요소에는 속성이 Element있으며 Counter필요한 정보를 검색합니다.

마지막으로, 찾고있는 사전이라면

var query = lst.GroupBy(x => x)
              .Where(g => g.Count() > 1)
              .ToDictionary(x => x.Key, y => y.Count());

그러면 요소를 키로 사용하고 값으로 반복되는 횟수를 가진 사전을 반환합니다.


이제 놀랍게도, 복제 된 int가 n int 배열로 분배된다고 가정 해보십시오. 사전을 사용하고 im을 사용하여 어떤 배열에 중복이 포함되어 있고 분배 논리에 따라 제거하는지 알고 싶다면 가장 빠른 방법이 있습니까? 그 결과를 달성? 관심을 가져 주셔서 감사합니다.
Mirko Arcese

나는 다음과 같은 일을하고있다 : code for (int i = 0; i <duplicates.Count; i ++) {int duplicate = duplicates [i]; duplicatesLocation.Add (중복, 새 목록 <int> ()); for (int k = 0; k <hitsList.Length; k ++) {if (hitsList [k] .Contains (duplicate)) {duplicatesLocation.ElementAt (i) .Value.Add (k); }} // 일부 규칙에 따라 중복 항목을 제거합니다. }code
Mirko Arcese

배열 목록에서 중복 항목을 찾으려면 SelectMany
Save

나는 목록의 배열에서 중복을 찾고 있지만 selectmany가 그것을 만드는 데 어떻게 도움이 될 수
없었는가

1
Count () 대신 Skip (1) .Any ()를 사용하는 것이 더 효율적인 경우 컬렉션에 둘 이상의 요소가 있는지 확인합니다. 1000 개의 요소가있는 컬렉션을 상상해보십시오. Skip (1). Any ()는 두 번째 요소를 찾으면 1 이상이 있음을 감지합니다. Count ()를 사용하려면 전체 컬렉션에 액세스해야합니다.
Harald Coppoolse

133

열거 형에 중복이 포함되어 있는지 확인하십시오 .

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

있는지 알아보십시오 모든 열거 가능한의 값은 고유 한 :

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

이것이 항상 부울 반대가 아닐 가능성이 있습니까? 모든 경우에 anyDuplicate ==! allUnique.
Garr Godfrey

1
@GarrGodfrey 그들은 항상 부울 반대입니다
Caltor

21

다른 방법은 HashSet .

var hash = new HashSet<int>();
var duplicates = list.Where(i => !hash.Add(i));

중복 목록에서 고유 한 값을 원하는 경우 :

var myhash = new HashSet<int>();
var mylist = new List<int>(){1,1,2,2,3,3,3,4,4,4};
var duplicates = mylist.Where(item => !myhash.Add(item)).Distinct().ToList();

다음은 일반적인 확장 방법과 동일한 솔루션입니다.

public static class Extensions
{
  public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector, IEqualityComparer<TKey> comparer)
  {
    var hash = new HashSet<TKey>(comparer);
    return source.Where(item => !hash.Add(selector(item))).ToList();
  }

  public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer)
  {
    return source.GetDuplicates(x => x, comparer);      
  }

  public static IEnumerable<TSource> GetDuplicates<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> selector)
  {
    return source.GetDuplicates(selector, null);
  }

  public static IEnumerable<TSource> GetDuplicates<TSource>(this IEnumerable<TSource> source)
  {
    return source.GetDuplicates(x => x, null);
  }
}

예상대로 작동하지 않습니다. List<int> { 1, 2, 3, 4, 5, 2 }소스로 사용 하면 결과는 (정확한 중복 값이 ​​2 인) IEnumerable<int>값을 가진 하나의 요소를 갖습니다.1
BCA

어제 @BCA, 당신이 틀렸다고 생각합니다. 이 예제를 확인하십시오 : dotnetfiddle.net/GUnhUl
HuBeZa

바이올린이 올바른 결과를 인쇄합니다. 그러나 그 Console.WriteLine("Count: {0}", duplicates.Count());바로 아래에 줄을 추가하면 인쇄 6됩니다. 이 기능의 요구 사항에 대해 빠진 것이 아니라면 결과 모음에 하나의 항목 만 있어야합니다.
BCA

@BCA는 어제 LINQ 연기 된 실행으로 인한 버그입니다. ToList문제를 해결하기 위해 추가 했지만 결과를 반복 할 때가 아니라 호출 된 즉시 메소드가 실행됨을 의미합니다.
HuBeZa

var hash = new HashSet<int>(); var duplicates = list.Where(i => !hash.Add(i));모든 중복 항목이 포함 된 목록으로 연결됩니다. 따라서 목록에 4가 4 번 있으면 중복 목록에 2가 3 번 나타납니다. 2 중 하나만 HashSet에 추가 할 수 있기 때문입니다. 목록에 각 복제본에 대해 고유 한 값을 포함 시키려면이 코드를 대신 사용하십시오.var duplicates = mylist.Where(item => !myhash.Add(item)).ToList().Distinct().ToList();
solid_luffy

10

당신은 이것을 할 수 있습니다 :

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();
    }
}

Duplicates 메서드에서 IsMultiple ()을 사용하면 전체 컬렉션을 반복하지 않기 때문에 Count ()보다 빠릅니다.


당신이 보면 그룹화에 대한 참조 소스 당신은이 볼 수 Count() 있다 계산 솔루션 가능성이 느립니다 사전.
Johnbot

@ 존봇. 이 경우 더 빠르며 구현이 변경되지 않을 가능성이 있지만 IGrouping 뒤에 구현 클래스의 구현 세부 사항에 달려 있습니다. 내 구현으로 전체 컬렉션을 반복하지 않을 것입니다.
Alex Siepman

[ Count()] 계산 은 기본적으로 전체 목록을 반복하는 것과 다릅니다. Count()사전 계산되지만 전체 목록을 반복하는 것은 아닙니다.
Jogi

@rehan 칸 : 나는 카운트 (차이를 이해)와 ()에 포함되지 않습니다
알렉스 Siepman

2
@RehanKhan : IsMultiple이 Count ()를 수행하지 않고 2 개의 항목이 끝난 후 즉시 중지됩니다. Take (2)와 마찬가지로 Count> = 2;
Alex Siepman

6

나는 당신이 당신의 프로젝트에서 그것을 포함 할 수있는 이것에 대한 반응에 대한 확장을 만들었습니다 .List 또는 Linq에서 중복을 검색 할 때 이것이 가장 큰 경우라고 생각합니다.

예:

//Dummy class to compare in list
public class Person
{
    public int Id { get; set; }
    public string Name { get; set; }
    public string Surname { get; set; }
    public Person(int id, string name, string surname)
    {
        this.Id = id;
        this.Name = name;
        this.Surname = surname;
    }
}


//The extention static class
public static class Extention
{
    public static IEnumerable<T> getMoreThanOnceRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
    { //Return only the second and next reptition
        return extList
            .GroupBy(groupProps)
            .SelectMany(z => z.Skip(1)); //Skip the first occur and return all the others that repeats
    }
    public static IEnumerable<T> getAllRepeated<T>(this IEnumerable<T> extList, Func<T, object> groupProps) where T : class
    {
        //Get All the lines that has repeating
        return extList
            .GroupBy(groupProps)
            .Where(z => z.Count() > 1) //Filter only the distinct one
            .SelectMany(z => z);//All in where has to be retuned
    }
}

//how to use it:
void DuplicateExample()
{
    //Populate List
    List<Person> PersonsLst = new List<Person>(){
    new Person(1,"Ricardo","Figueiredo"), //fist Duplicate to the example
    new Person(2,"Ana","Figueiredo"),
    new Person(3,"Ricardo","Figueiredo"),//second Duplicate to the example
    new Person(4,"Margarida","Figueiredo"),
    new Person(5,"Ricardo","Figueiredo")//third Duplicate to the example
    };

    Console.WriteLine("All:");
    PersonsLst.ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        All:
        1 -> Ricardo Figueiredo
        2 -> Ana Figueiredo
        3 -> Ricardo Figueiredo
        4 -> Margarida Figueiredo
        5 -> Ricardo Figueiredo
        */

    Console.WriteLine("All lines with repeated data");
    PersonsLst.getAllRepeated(z => new { z.Name, z.Surname })
        .ToList()
        .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        All lines with repeated data
        1 -> Ricardo Figueiredo
        3 -> Ricardo Figueiredo
        5 -> Ricardo Figueiredo
        */
    Console.WriteLine("Only Repeated more than once");
    PersonsLst.getMoreThanOnceRepeated(z => new { z.Name, z.Surname })
        .ToList()
        .ForEach(z => Console.WriteLine("{0} -> {1} {2}", z.Id, z.Name, z.Surname));
    /* OUTPUT:
        Only Repeated more than once
        3 -> Ricardo Figueiredo
        5 -> Ricardo Figueiredo
        */
}

1
Count () 대신 Skip (1) .Any ()를 사용하십시오. 중복이 1000 개인 경우 Skip (1) .Any ()는 두 번째 사본을 찾은 후에 중지됩니다. Count ()는 1000 개의 모든 요소에 액세스합니다.
Harald Coppoolse

1
이 확장 방법을 추가하는 경우 다른 답변 중 하나에서 제안한 것처럼 GroupBy 대신 HashSet.Add를 사용하는 것이 좋습니다. HashSet.Add가 중복을 발견하면 중지됩니다. 하나 이상의 요소를 가진 그룹이 발견 된 경우에도 GroupBy는 모든 요소를 ​​계속 그룹화합니다.
Harald Coppoolse

6

중복 값만 찾으려면 다음을 수행하십시오.

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

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

따라서 group by는 숫자를 키로 그룹화하고 카운트 (반복 횟수)를 유지합니다. 그 후, 우리는 두 번 이상 반복 한 값을 확인하고 있습니다.

uniuqe 값만 찾으려면 다음을 수행하십시오.

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

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

따라서 group by는 숫자를 키로 그룹화하고 카운트 (반복 횟수)를 유지합니다. 그 후, 우리는 한 번만 반복 한 값이 고유하다는 것을 확인하고 있습니다.


아래 코드는 고유 항목을 찾습니다. var unique = list.Distinct(x => x)
Malu MN

1

MS SQL Server에서 확인 된 중복 함수의 Linq 대 SQL 확장의 전체 세트. .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()));
}

0

답이 있지만 왜 작동하지 않는지 이해하지 못했습니다.

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();
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.