linq查询从对象列表中返回不同的字段值

ast*_*ght 78 c# linq

class obj
{
    int typeID; //10 types  0-9 
    string uniqueString; //this is unique
}
Run Code Online (Sandbox Code Playgroud)

假设有包含100个obj元素的列表,但只有10个唯一的typeID.
是否可以写一个LINQ查询从objs列表中返回10个唯一的int?

Ars*_*yan 138

objList.Select(o=>o.typeId).Distinct()
Run Code Online (Sandbox Code Playgroud)

  • 第二种形式似乎使用了Distinct的重载,据我所知,它不存在. (2认同)
  • 正如乔恩·斯基特(Jon Skeet)所述,这只会返回“选择”中指定的属性。 (2认同)

Jon*_*eet 47

假设你想要完整的对象,但只想处理清晰度typeID,那么LINQ中没有任何东西可以让它变得简单.(如果你只是想要这些typeID值,那么很容易 - 用它进行投射Select,然后使用正常的Distinct调用.)

MoreLINQ中,我们有DistinctBy您可以使用的运算符:

var distinct = list.DistinctBy(x => x.typeID);
Run Code Online (Sandbox Code Playgroud)

这仅适用于LINQ to Objects.

你可以使用分组或查找,这有点烦人和低效:

var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());
Run Code Online (Sandbox Code Playgroud)

  • @Shil:不,我正在写有关 MoreLINQ 中的 DistinctBy 的文章。与 Microsoft.Ajax.Utilities 无关。 (2认同)
  • @DipenduPaul:是的,但这仍然意味着为给定的属性创建一个相等比较器,这很烦人并且很难阅读。如果您可以采用 MoreLINQ 依赖项,我认为那就更干净了。 (2认同)

小智 20

如果只想使用纯Linq,可以使用groupby:

List<obj> distinct =
  objs.GroupBy(car => car.typeID).Select(g => g.First()).ToList();
Run Code Online (Sandbox Code Playgroud)

如果您希望在整个应用中使用方法:

public static IEnumerable<TSource> DistinctBy<TSource, TKey>
    (this IEnumerable<TSource> source, Func<TSource, TKey> keySelector)
{
    HashSet<TKey> seenKeys = new HashSet<TKey>();
    foreach (TSource element in source)
    {
        if (!seenKeys.Contains(keySelector(element)))
        {
            seenKeys.Add(keySelector(element));
            yield return element;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

正如MoreLinq所做的那样

使用此方法仅使用Id属性查找不同的值,您可以使用:

var query = objs.DistinctBy(p => p.TypeId);
Run Code Online (Sandbox Code Playgroud)

你可以使用多个属性:

var query = objs.DistinctBy(p => new { p.TypeId, p.Name });
Run Code Online (Sandbox Code Playgroud)

  • .NET 6 现在具有distinctBy 扩展方法。[文档](https://learn.microsoft.com/en-us/dotnet/api/system.linq.enumerable.distinctby?view=net-6.0) (4认同)

Don*_*nut 6

当然,使用Enumerable.Distinct.

给定obj(例如foo)的集合,你会做这样的事情:

var distinctTypeIDs = foo.Select(x => x.typeID).Distinct();
Run Code Online (Sandbox Code Playgroud)


Gag*_*age 5

我认为这就是你要找的:

    var objs= (from c in List_Objects 
orderby c.TypeID  select c).GroupBy(g=>g.TypeID).Select(x=>x.FirstOrDefault());      
Run Code Online (Sandbox Code Playgroud)

类似于此使用 LINQ 返回不同的 IQueryable?

  • 您可以使用“GroupBy”的替代重载来使这也变得更简单 - 请参阅我的答案以获取示例。 (2认同)

Rez*_*abi 5

如果只想使用 Linq,您可以重写EqualsGetHashCode方法。

产品类别:

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


    public override bool Equals(object obj)
    {
        if (!(obj is Product))
        {
            return false;
        }

        var other = (Product)obj;
        return Id == other.Id;
    }

    public override int GetHashCode()
    {
        return Id.GetHashCode();
    }
}
Run Code Online (Sandbox Code Playgroud)

主要方法:

static void Main(string[] args)
    {

        var products = new List<Product>
        {
            new Product{ ProductName="Product 1",Id = 1},
            new Product{ ProductName="Product 2",Id = 2},
            new Product{ ProductName="Product 4",Id = 5},
            new Product{ ProductName="Product 3",Id = 3},
            new Product{ ProductName="Product 4",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
            new Product{ ProductName="Product 6",Id = 4},
        };

        var itemsDistinctByProductName = products.Distinct().ToList();

        foreach (var product in itemsDistinctByProductName)
        {
            Console.WriteLine($"Product Id : {product.Id} ProductName : {product.ProductName} ");
        }

        Console.ReadKey();
    }
Run Code Online (Sandbox Code Playgroud)