English 中文(简体)
如何使用有多个字段的 LINQ 区别 ()
原标题:How to use LINQ Distinct() with multiple fields

我从一个数据库(简化)中得出以下“强度”EF等级

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

ProductionId 是表格的“强”基本键

对于 DB 设计师做出的错误设计决定( 我无法修改它), 本表中有 < code> CategoryId 和 < code>CategoryName

我需要一个 < 强度 > 拖放列表 , 配有 < code > CategoryId , 配有 < 强度 > Value 和 < code> CategoryName , 配有 < 强度 > Text 。 因此,我应用了以下代码 :

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

从逻辑上讲,它应该创建一个具有以下属性的匿名对象: CategoryId CategoryName Distinct () 保证没有重复的对(CategoryId , CategoryName )。

但实际上它不起作用。 就我所理解的Distinct () () 只是当收藏中只有一个字段时才起作用, 否则它就忽略了它们... 是否正确? 是否有任何变通方法? 谢谢!

<强> UPDATE

抱歉 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})
最佳回答

我假设您在列表上使用不同的方法。 您需要使用查询结果作为数据源, 用于您的 DownList, 例如通过 < code> 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();

第三个选项是使用"https://github.com/morelinq/MoreLINQ/blob/master/MoreLinq/DistinctBy.cs" rel=“noreferrer”>MoreLinq s DistinctBy 。

问题回答

区别() 保证没有重复配对( 类别Id、 类别Name) 。

- 正是

匿名类型 神奇地执行 Equols GetHashcode

我假设在某个地方又犯了一个错误 案件敏感度 变异类 无法比较的字段

这是我的解决方案,它支持不同类型的关键选择者:

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)

在您选中的域中使用 < code> Key 关键字将有效, 如下面 。

product. select (m)\\\\ gt; 新{Key m. CategoryId, 键 m. CategoryName}. distict ();

我意识到这是一条旧线, 但认为这对一些人有帮助。 我在 VB. NET 与. NET 合作时通常会输入代码, 所以 < code> Key 可能会以不同方式转换为 C # 。

< a href="""http://msdn.microsoft.com/en-us/library/system.linq.enumberable.grafle.aspx" rel="noreferr" >Distinct 方法返回一个序列的不同元素。

如果您用反射器查看其执行, 您就会看到它为您的匿名类型创建了 < code> DistinctListerator 。 当对收藏进行统计时, 不同的代号会将元素添加到 < code> set 。 这个代号会跳过所有已经在 < code> set 中包含的元素 。 < code> set 使用 < code> GetHashCode 和 < code> Eduals 方法来定义元素是否在 < code> < set 中存在 。

GetHashCode Equals 如何为匿名类型而实施?正如它在上所说,http://msdn.microsoft.com/en-us/library/bb397696.aspx" rel=“noreferr'>msdn :

Equals and GetHashCode methods on anonymous types are defined in terms of the Equals and GetHashcode methods of the properties, two instances of the same anonymous type are equal only if all their properties are equal.

所以,您肯定应该有不同的匿名对象, 当重复不同的收藏时。 结果并不取决于您使用的匿名类型字段数 。

回答问题的标题(这里吸引了多少人), 忽略这个例子使用匿名类型...

这一解决方案还将适用于非匿名类型,而不应适用于匿名类型。

帮助班 :

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

最简单( 但效率不高) 的用法是映射到字符串表达式, 以避免自定义散列 。 等字符串已经有相同的散列代码 。

Reference:
Wrap a delegate in an IEqualityComparer

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;

    }

解决你问题的办法看起来是这样的:

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




相关问题
Anyone feel like passing it forward?

I m the only developer in my company, and am getting along well as an autodidact, but I know I m missing out on the education one gets from working with and having code reviewed by more senior devs. ...

NSArray s, Primitive types and Boxing Oh My!

I m pretty new to the Objective-C world and I have a long history with .net/C# so naturally I m inclined to use my C# wits. Now here s the question: I feel really inclined to create some type of ...

C# Marshal / Pinvoke CBitmap?

I cannot figure out how to marshal a C++ CBitmap to a C# Bitmap or Image class. My import looks like this: [DllImport(@"test.dll", CharSet = CharSet.Unicode)] public static extern IntPtr ...

How to Use Ghostscript DLL to convert PDF to PDF/A

How to user GhostScript DLL to convert PDF to PDF/A. I know I kind of have to call the exported function of gsdll32.dll whose name is gsapi_init_with_args, but how do i pass the right arguments? BTW, ...

Linqy no matchy

Maybe it s something I m doing wrong. I m just learning Linq because I m bored. And so far so good. I made a little program and it basically just outputs all matches (foreach) into a label control. ...

热门标签