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


89
class obj
{
    int typeId; //10 types  0-9 
    string uniqueString; //this is unique
}

假设存在一个列表,其中包含obj的100个元素,但只有10个唯一的typeID。
是否可以编写LINQ查询以从objs列表中返回10个唯一的整数?


这个问题是如此简单,不适合悬赏。
思想家

Answers:



58

假设您要使用完整的对象,但只想通过来处理不同性typeID,则LINQ中没有内置任何东西可以使此操作变得容易。(如果您想要这些typeID值,这很容易-Select使用该项目进行投影,然后使用常规Distinct调用。)

MoreLINQ我们有DistinctBy运营商,你可以使用:

var distinct = list.DistinctBy(x => x.typeID);

但是,这仅适用于LINQ to Objects。

您可以使用分组或查找,这有点烦人并且效率低下:

var distinct = list.GroupBy(x => x.typeID, (key, group) => group.First());

要使DistinctBy出现,您需要添加名称空间Microsoft.Ajax.Utilities
Shiljo Paulson

1
@Shil:不,我在MoreLINQ中写有关DistinctBy的文章。与Microsoft.Ajax.Utilities无关。
乔恩·斯基特

现在我可以看到LINQ中有大量Distinct,它以IEqualityComparer作为参数并根据IEqualityComparer中方法的实现返回不同的对象列表
Dipendu Paul

1
@DipenduPaul:是的,但这仍然意味着为给定的属性创建一个相等比较器,这很烦人,并且使其难以阅读。如果您可以使用MoreLINQ依赖关系,我认为这更干净。
乔恩·斯基特

22

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

List<obj> distinct =
  objs.GroupBy(car => car.typeID).Select(g => g.First()).ToList();

如果要在整个应用程序中使用一种方法,则类似于MoreLinq所做的事情:

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

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

var query = objs.DistinctBy(p => p.TypeId);

您可以使用多个属性:

var query = objs.DistinctBy(p => new { p.TypeId, p.Name });

感谢您的多重属性部分!


5

我认为这是您要寻找的:

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

与此类似,用LINQ返回不同的IQueryable吗?


.First很好,因为如果其中没有任何内容,您将不会有该小组。
mqp 2011年

1
您也可以使用替代的重载GroupBy来简化此操作-请参见我的示例示例。
乔恩·斯基特

3

如果只想使用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();
    }
}

主要方法:

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

1

我想将特定的数据绑定到下拉列表,它应该与众不同。我做了以下事情:

List<ClassDetails> classDetails;
List<string> classDetailsData = classDetails.Select(dt => dt.Data).Distinct.ToList();
ddlData.DataSource = classDetailsData;
ddlData.Databind();

看看是否有帮助

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.