Programming

LINQ : 고유 한 값

procodes 2020. 6. 29. 21:49
반응형

LINQ : 고유 한 값


XML에서 다음 항목 세트가 있습니다.

id           category

5            1
5            3
5            4
5            3
5            3

이 항목들에 대한 명확한 목록이 필요합니다.

5            1
5            3
5            4

LINQ에서 카테고리와 ID를 어떻게 구분할 수 있습니까?


하나 이상의 필드로 구별하려고합니까? 그렇다면 익명 유형과 고유 연산자를 사용하십시오.

var query = doc.Elements("whatever")
               .Select(element => new {
                             id = (int) element.Attribute("id"),
                             category = (int) element.Attribute("cat") })
               .Distinct();

"더 큰"유형의 고유 한 값 세트를 가져 오려고 하지만 고유성 측면에 대한 특성의 일부 서브 세트 만보고자한다면 MoreLINQ 에서 다음 DistinctBy과 같이 구현하고 싶을 것 입니다 DistinctBy.cs.

 public static IEnumerable<TSource> DistinctBy<TSource, TKey>(
     this IEnumerable<TSource> source,
     Func<TSource, TKey> keySelector,
     IEqualityComparer<TKey> comparer)
 {
     HashSet<TKey> knownKeys = new HashSet<TKey>(comparer);
     foreach (TSource element in source)
     {
         if (knownKeys.Add(keySelector(element)))
         {
             yield return element;
         }
     }
 }

null비교 자로 전달 하면 키 유형에 기본 비교기가 사용됩니다.


Distinct()자신의 비교기와 함께 사용하십시오 .

http://msdn.microsoft.com/en-us/library/bb338049.aspx


Jon Skeet의 답변 외에도 그룹을 표현식별로 사용하여 각 그룹 반복 횟수에 따라 고유 그룹을 가져올 수 있습니다.

var query = from e in doc.Elements("whatever")
            group e by new { id = e.Key, val = e.Value } into g
            select new { id = g.Key.id, val = g.Key.val, count = g.Count() };

여전히 찾고있는 사람이라면 다음은 커스텀 람다 비교기를 구현하는 또 다른 방법입니다.

public class LambdaComparer<T> : IEqualityComparer<T>
    {
        private readonly Func<T, T, bool> _expression;

        public LambdaComparer(Func<T, T, bool> lambda)
        {
            _expression = lambda;
        }

        public bool Equals(T x, T y)
        {
            return _expression(x, y);
        }

        public int GetHashCode(T obj)
        {
            /*
             If you just return 0 for the hash the Equals comparer will kick in. 
             The underlying evaluation checks the hash and then short circuits the evaluation if it is false.
             Otherwise, it checks the Equals. If you force the hash to be true (by assuming 0 for both objects), 
             you will always fall through to the Equals check which is what we are always going for.
            */
            return 0;
        }
    }

그런 다음 람다에 걸릴 수있는 linq Distinct에 대한 확장을 만들 수 있습니다

   public static IEnumerable<T> Distinct<T>(this IEnumerable<T> list,  Func<T, T, bool> lambda)
        {
            return list.Distinct(new LambdaComparer<T>(lambda));
        }  

용법:

var availableItems = list.Distinct((p, p1) => p.Id== p1.Id);

답변에 약간 늦었지만 그룹화하려는 값뿐만 아니라 전체 요소를 원할 경우이 작업을 수행 할 수 있습니다.

var query = doc.Elements("whatever")
               .GroupBy(element => new {
                             id = (int) element.Attribute("id"),
                             category = (int) element.Attribute("cat") })
               .Select(e => e.First());

이렇게하면 DistinctBy를 사용하는 Jon Skeets의 두 번째 예와 유사하지만 IEqualityComparer 비교기를 구현하지 않고도 선택에 따라 그룹과 일치하는 첫 번째 전체 요소가 제공됩니다. DistinctBy가 더 빠를 가능성이 높지만 성능에 문제가없는 경우 위의 솔루션에는 더 적은 코드가 포함됩니다.


// First Get DataTable as dt
// DataRowComparer Compare columns numbers in each row & data in each row

IEnumerable<DataRow> Distinct = dt.AsEnumerable().Distinct(DataRowComparer.Default);

foreach (DataRow row in Distinct)
{
    Console.WriteLine("{0,-15} {1,-15}",
        row.Field<int>(0),
        row.Field<string>(1)); 
}

Since we are talking about having every element exactly once, a "set" makes more sense to me.

Example with classes and IEqualityComparer implemented:

 public class Product
    {
        public int Id { get; set; }
        public string Name { get; set; }

        public Product(int x, string y)
        {
            Id = x;
            Name = y;
        }
    }

    public class ProductCompare : IEqualityComparer<Product>
    {
        public bool Equals(Product x, Product y)
        {  //Check whether the compared objects reference the same data.
            if (Object.ReferenceEquals(x, y)) return true;

            //Check whether any of the compared objects is null.
            if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
                return false;

            //Check whether the products' properties are equal.
            return x.Id == y.Id && x.Name == y.Name;
        }
        public int GetHashCode(Product product)
        {
            //Check whether the object is null
            if (Object.ReferenceEquals(product, null)) return 0;

            //Get hash code for the Name field if it is not null.
            int hashProductName = product.Name == null ? 0 : product.Name.GetHashCode();

            //Get hash code for the Code field.
            int hashProductCode = product.Id.GetHashCode();

            //Calculate the hash code for the product.
            return hashProductName ^ hashProductCode;
        }
    }

Now

List<Product> originalList = new List<Product> {new Product(1, "ad"), new Product(1, "ad")};
var setList = new HashSet<Product>(originalList, new ProductCompare()).ToList();

setList will have unique elements

I thought of this while dealing with .Except() which returns a set-difference

참고URL : https://stackoverflow.com/questions/998066/linq-distinct-values

반응형