85

私はデータベースから派生した次のEFクラスを持っています(簡略化)

class Product
{ 
     public string ProductId;
     public string ProductName;
     public string CategoryId;
     public string CategoryName;
}

ProductIdテーブルの主キーです。

DBデザイナによって行われた悪い設計決定(私はそれを変更することはできません)のために、私はこの表にCategoryIdあります。CategoryName

(distinct)をValueおよびTextとして持つDropDownListが必要です。したがって、次のコードを適用しました。CategoryIdCategoryName

product.Select(m => new {m.CategoryId, m.CategoryName}).Distinct();

CategoryId論理的には、プロパティとしておよびを使用して匿名オブジェクトを作成する必要がありCategoryNameます。重複ペア( 、 )Distinct()がないことを保証します。 CategoryIdCategoryName

しかし、実際には機能しません。コレクションにフィールドが1つしかない場合の作品を理解している限り、Distinct()それ以外の場合は無視されます...正しいですか?回避策はありますか?ありがとう!

アップデート

申し訳ありませんproductが:

List<Product> product = new List<Product>();

私は同じ結果を得る別の方法を見つけましたDistinct()

product.GroupBy(d => new {d.CategoryId, d.CategoryName}) 
       .Select(m => new {m.Key.CategoryId, m.Key.CategoryName})
4

10 に答える 10

83

リストのメソッド呼び出しのように、distinctを使用していると思います。クエリの結果をDropDownListのデータソースとして使用する必要があります。たとえば、を介して具体化する必要がありますToList

var distinctCategories = product
                        .Select(m => new {m.CategoryId, m.CategoryName})
                        .Distinct()
                        .ToList();
DropDownList1.DataSource     = distinctCategories;
DropDownList1.DataTextField  = "CategoryName";
DropDownList1.DataValueField = "CategoryId";

プロパティが少ない匿名タイプの代わりに実際のオブジェクトが必要な場合の別の方法は、匿名タイプで使用することGroupByです。

List<Product> distinctProductList = product
    .GroupBy(m => new {m.CategoryId, m.CategoryName})
    .Select(group => group.First())  // instead of First you can also apply your logic here what you want to take, for example an OrderBy
    .ToList();

3番目のオプションは、MoreLinqDistinctByを使用することです。

于 2012-05-23T12:38:20.427 に答える
11

Distinct()は、重複ペア(CategoryId、CategoryName)がないことを保証します。

-まさにその

匿名タイプは「魔法のように」実装Equalsし、GetHashcode

どこかで別のエラーを想定しています。大文字と小文字の区別?可変クラス?比較できないフィールド?

于 2012-05-23T12:31:51.967 に答える
6

これは私の解決策であり、さまざまなタイプのkeySelectorsをサポートしています。

public static IEnumerable<TSource> DistinctBy<TSource>(this IEnumerable<TSource> source, params Func<TSource, object>[] keySelectors)
{
    // initialize the table
    var seenKeysTable = keySelectors.ToDictionary(x => x, x => new HashSet<object>());

    // loop through each element in source
    foreach (var element in source)
    {
        // initialize the flag to true
        var flag = true;

        // loop through each keySelector a
        foreach (var (keySelector, hashSet) in seenKeysTable)
        {                    
            // if all conditions are true
            flag = flag && hashSet.Add(keySelector(element));
        }

        // if no duplicate key was added to table, then yield the list element
        if (flag)
        {
            yield return element;
        }
    }
}

それを使用するには:

list.DistinctBy(d => d.CategoryId, d => d.CategoryName)
于 2018-03-19T21:32:15.840 に答える
5

Key以下のように、選択したキーワードを使用すると機能します。

product.Select(m => new {Key m.CategoryId, Key m.CategoryName}).Distinct();

私はこれが古いスレッドを引き起こしていることを理解していますが、それが何人かの人々を助けるかもしれないと考えました。私は通常、.NETを使用するときにVB.NETでコーディングするためKey、C#への変換が異なる場合があります。

于 2014-03-30T06:00:46.683 に答える
4

Distinctメソッドは、シーケンスから個別の要素を返します。

DistinctIteratorReflectorを使用した実装を見ると、匿名タイプ用に作成されていることがわかります。個別のイテレータはSet、コレクションを列挙するときに要素を追加します。この列挙子は、すでににあるすべての要素をスキップしますSet。要素がにすでに存在するかどうかを定義するためのSet使用GetHashCodeとメソッド。EqualsSet

匿名タイプの場合、どのようGetHashCodeに実装されますか?msdnEqualsで述べたように:

匿名型のEqualsメソッドとGetHashCodeメソッドは、プロパティのEqualsメソッドとGetHashcodeメソッドで定義されます。同じ匿名型の2つのインスタンスは、すべてのプロパティが等しい場合にのみ等しくなります。

したがって、個別のコレクションを反復処理する場合は、必ず個別の匿名オブジェクトを使用する必要があります。また、結果は、匿名型に使用するフィールドの数に依存しません。

于 2012-05-23T13:04:34.990 に答える
4

質問の見出し(ここで人々を惹きつけたもの)に答え、例が匿名タイプを使用したことを無視します。

このソリューションは、匿名でないタイプでも機能します。匿名タイプには必要ありません。

ヘルパークラス:

/// <summary>
/// Allow IEqualityComparer to be configured within a lambda expression.
/// From https://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer
/// </summary>
/// <typeparam name="T"></typeparam>
public class LambdaEqualityComparer<T> : IEqualityComparer<T>
{
    readonly Func<T, T, bool> _comparer;
    readonly Func<T, int> _hash;

    /// <summary>
    /// Simplest constructor, provide a conversion to string for type T to use as a comparison key (GetHashCode() and Equals().
    /// https://stackoverflow.com/questions/98033/wrap-a-delegate-in-an-iequalitycomparer, user "orip"
    /// </summary>
    /// <param name="toString"></param>
    public LambdaEqualityComparer(Func<T, string> toString)
        : this((t1, t2) => toString(t1) == toString(t2), t => toString(t).GetHashCode())
    {
    }

    /// <summary>
    /// Constructor.  Assumes T.GetHashCode() is accurate.
    /// </summary>
    /// <param name="comparer"></param>
    public LambdaEqualityComparer(Func<T, T, bool> comparer)
        : this(comparer, t => t.GetHashCode())
    {
    }

    /// <summary>
    /// Constructor, provide a equality comparer and a hash.
    /// </summary>
    /// <param name="comparer"></param>
    /// <param name="hash"></param>
    public LambdaEqualityComparer(Func<T, T, bool> comparer, Func<T, int> hash)
    {
        _comparer = comparer;
        _hash = hash;
    }

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

    public int GetHashCode(T obj)
    {
        return _hash(obj);
    }    
}

最も簡単な使用法:

List<Product> products = duplicatedProducts.Distinct(
    new LambdaEqualityComparer<Product>(p =>
        String.Format("{0}{1}{2}{3}",
            p.ProductId,
            p.ProductName,
            p.CategoryId,
            p.CategoryName))
        ).ToList();

最も単純な(しかしそれほど効率的ではない)使用法は、カスタムハッシュが回避されるように、文字列表現にマップすることです。等しい文字列にはすでに等しいハッシュコードがあります。

参照:
IEqualityComparerでデリゲートをラップします

于 2017-03-24T22:47:57.763 に答える
1
public List<ItemCustom2> GetBrandListByCat(int id)
    {

        var OBJ = (from a in db.Items
                   join b in db.Brands on a.BrandId equals b.Id into abc1
                   where (a.ItemCategoryId == id)
                   from b in abc1.DefaultIfEmpty()
                   select new
                   {
                       ItemCategoryId = a.ItemCategoryId,
                       Brand_Name = b.Name,
                       Brand_Id = b.Id,
                       Brand_Pic = b.Pic,

                   }).Distinct();


        List<ItemCustom2> ob = new List<ItemCustom2>();
        foreach (var item in OBJ)
        {
            ItemCustom2 abc = new ItemCustom2();
            abc.CategoryId = item.ItemCategoryId;
            abc.BrandId = item.Brand_Id;
            abc.BrandName = item.Brand_Name;
            abc.BrandPic = item.Brand_Pic;
            ob.Add(abc);
        }
        return ob;

    }
于 2018-01-22T05:36:11.937 に答える
1

.net6のアップデートDistinctByが追加されました。

myQueryable.DistinctBy(c => new { c.KeyA, c.KeyB});

https://docs.microsoft.com/en-us/dotnet/api/system.linq.queryable.distinctby?view=net-6.0

IQueryable(との両方IEnumerable

于 2021-11-17T14:35:33.970 に答える
0

問題の解決策は次のようになります。

public class Category {
  public long CategoryId { get; set; }
  public string CategoryName { get; set; }
} 

..。

public class CategoryEqualityComparer : IEqualityComparer<Category>
{
   public bool Equals(Category x, Category y)
     => x.CategoryId.Equals(y.CategoryId)
          && x.CategoryName .Equals(y.CategoryName, 
 StringComparison.OrdinalIgnoreCase);

   public int GetHashCode(Mapping obj)
     => obj == null 
         ? 0
         : obj.CategoryId.GetHashCode()
           ^ obj.CategoryName.GetHashCode();
}

..。

 var distinctCategories = product
     .Select(_ => 
        new Category {
           CategoryId = _.CategoryId, 
           CategoryName = _.CategoryName
        })
     .Distinct(new CategoryEqualityComparer())
     .ToList();
于 2020-02-26T11:21:49.240 に答える
-3
Employee emp1 = new Employee() { ID = 1, Name = "Narendra1", Salary = 11111, Experience = 3, Age = 30 };Employee emp2 = new Employee() { ID = 2, Name = "Narendra2", Salary = 21111, Experience = 10, Age = 38 };
Employee emp3 = new Employee() { ID = 3, Name = "Narendra3", Salary = 31111, Experience = 4, Age = 33 };
Employee emp4 = new Employee() { ID = 3, Name = "Narendra4", Salary = 41111, Experience = 7, Age = 33 };

List<Employee> lstEmployee = new List<Employee>();

lstEmployee.Add(emp1);
lstEmployee.Add(emp2);
lstEmployee.Add(emp3);
lstEmployee.Add(emp4);

var eemmppss=lstEmployee.Select(cc=>new {cc.ID,cc.Age}).Distinct();
于 2014-10-21T08:25:58.650 に答える