web-dev-qa-db-ja.com

LINQ:個別の値

XMLから次のアイテムセットがあります。

id           category

5            1
5            3
5            4
5            3
5            3

これらのアイテムの個別のリストが必要です。

5            1
5            3
5            4

LINQでカテゴリAND IDも区別するにはどうすればよいですか?

131
balint

複数のフィールドで区別しようとしていますか?その場合は、匿名型とDistinct演算子を使用するだけで問題ありません。

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

「より大きな」型の異なる値のセットを取得しようとしているが、異なる側面のプロパティのサブセットのみを見る場合、おそらく MoreLINQ で実装されているDistinctByが必要です。 = in 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を渡すと、キータイプにデフォルトの比較子が使用されます。)

211
Jon Skeet

Distinct()と独自の比較演算子を使用するだけです。

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

33
Stu

Jon Skeetの答えに加えて、group by式を使用して、各グループの反復回数に沿って一意のグループを取得することもできます。

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

まだ見ている人のために。カスタムラムダ比較器を実装する別の方法を次に示します。

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);
12
Ricky G

私は答えに少し遅れていますが、グループ化する値だけでなく、要素全体が必要な場合はこれを行うことができます:

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の2番目の例に似ていますが、IEqualityComparer比較子を実装せずに、選択によってグループに一致する最初の要素全体が得られます。 DistinctByはおそらくより高速になりますが、上記のソリューションでは、パフォーマンスが問題にならない場合、コードが少なくなります。

8
Olle Johansson
// 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)); 
}
4
Mohamed Elsayed

すべての要素を正確に1回持つことについて話しているので、「セット」は私にとってより意味があります。

クラスとIEqualityComparerを実装した例:

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

いま

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

setListには一意の要素があります

セット差分を返す.Except()を扱っているときにこれを考えました

0
Aditya A V S