使用LINQ的唯一项目列表

时间:2010-07-06 13:56:17

标签: c# linq silverlight list unique

我一直在使用LINQ一段时间了,但似乎是关于Unique项目的问题,我有下面的列表:

List<Stock> stock = new List<Stock>();

它具有以下属性:字符串ID,字符串类型,字符串描述,示例:

public class Stock
{
    public string ID { get; set; }
    public string Type { get; set; }
    public string Description { get; set; }
}

我希望有一个LINQ查询,它会按照类型对Stock中的项目进行分组,并将其作为新的Stock列表返回(它必须与原始Stock List的类型相同)。

示例数据:

 ID   Type                 Description
----------------------------------------------
  1   Kitchen Appliance    Dishwasher  
  2   Living Room          Television  
  3   Kitchen Appliance    Washing Machine  
  4   Kitchen Appliance    Fridge  

...

我的Linq查询希望能够返回所有的厨房用具示例 所以我将它作为“类型”传递给查询,它将返回项目1,3和4 来自此示例列表。

返回的列表也必须是List<Stock>类型。

基本上我想要一个按类型列出的唯一项目,类似于SQL Distinct查询,如何在LINQ中实现这一点?
替代解决方案很好,但必须只是Silverlight / C#客户端代码。

另一个澄清是,我也可能不提供参数“厨房用具”,可能只想要独特的参数,例如,它将返回厨房用具和起居室,只有一个类似于一个类别,无论多少那种类型有。

6 个答案:

答案 0 :(得分:44)

灵活的方法

使用GroupByToDictionary创建List<Stock>属性上键入的Type值字典:

var appliancesByType = stock
    .GroupBy(item => item.Type)
    .ToDictionary(grp => grp.Key, grp => grp.ToList());

然后,您可以非常轻松地访问类型本身以及任何给定类型的列表:

// List of unique type names only
List<string> stockTypes = appliancesByType.Keys.ToList();

// Or: list of one stock item per type
List<Stock> exampleStocks = appliancesByType
    .Select(kvp => kvp.Value[0])
    .ToList();

// List of stock items for a given type
List<Stock> kitchenAppliances = appliancesByType["Kitchen Appliance"];

正如我所看到的,这种方法确实可以满足您的所有需求。但是对于其他一些选项,请参见下文。

替代(快速和肮脏)方法

您始终可以使用Where来获取所需类型的项目,然后ToList将这些项目放入新的List<Stock>

List<Stock> kitchenAppliances = stock
    .Where(item => item.Type == "Kitchen Appliance")
    .ToList();

回应最后一部分:

  

另一个澄清是我   也可能不提供参数   “厨房用具”可能只是想要   独特的,例如它会   返回厨房用具和生活   房间一次,每次只有一种像   类别,无论多少   输入有。

在这里,您似乎想要完全不同的东西:基本上是Distinct提供的行为。对于此功能,您基本上可以使用Soonts's answer(可选地,返回IEnumerable<tKey>而不是IEnumerable<tSource>),或者您可以将Distinct与{{3}结合使用}避免需要实现IEqualityComparer<Stock>(见下文)。


更新

回应您的澄清,这是我的建议:两种方法,每种方法一种(Select):

// This will return a list of all Stock objects having the specified Type
static List<Stock> GetItemsForType(string type)
{
    return stock
        .Where(item => item.Type == type)
        .ToList();
}

// This will return a list of the names of all Type values (no duplicates)
static List<string> GetStockTypes()
{
    return stock
        .Select(item => item.Type)
        .Distinct()
        .ToList();
}

答案 1 :(得分:4)

听起来像是一个简单的Where子句需要。

List<Stock> kitchen= stock.Where(s=>s.Type=="Kitchen Appliance")
                          .OrderBy(s=>s.Description).ToList();

如果您想严格要求源列表中包含的Types

string[] typesFound = stock.Select(s=>s.Type).Distinct().ToArray();

答案 2 :(得分:3)

static class EnumerableEx
{
    // Selectively skip some elements from the input sequence based on their key uniqueness.
    // If several elements share the same key value, skip all but the 1-st one.
    public static IEnumerable<tSource> uniqueBy<tSource, tKey>( this IEnumerable<tSource> src, Func<tSource, tKey> keySelecta )
    {
        HashSet<tKey> res = new HashSet<tKey>();
        foreach( tSource e in src )
        {
            tKey k = keySelecta( e );
            if( res.Contains( k ) )
                continue;
            res.Add( k );
            yield return e;
        }
    }
}

// Then later in the code
List<Stock> res = src.uniqueBy( elt => elt.Type ).ToList()

答案 3 :(得分:3)

var kitchenAppliances = stocks.Where(stock => stock.Type == "Kitchen Appliance");

答案 4 :(得分:1)

我可能不明白这个问题,但这听起来像是一个非常简单的Linq查询:

List<Stock> stock = new List<Stock>();
... populate your list as per your example

List<Stock> kitchenAppliances =
    (from obj in stock
     where obj.Type == "Kitchen Appliance"
     select obj).ToList();

或者您更喜欢扩展方法语法:

List<Stock> kitchenAppliances =
    stock.Where(obj => obj.Type == "Kitchen Appliance").ToList();

我不明白的是你在这种情况下对独特和独特的使用。对象已经是唯一的,在我看来,你想要一个基本的查询“给我所有的厨房用具”。

答案 5 :(得分:1)

你也可以沿着这些方向做一些事情,在这种情况下我采取lucene结果然后将umbraco节点拉到匿名类型

var datasource = (from n in SearchResults
select new
{
  PageLink = uQuery.GetNode(n.Id).NiceUrl,
  uQuery.GetNode(n.Id).Name,
  Date =    uQuery.GetNode(n.Id).GetProperty("startDate"),
  IntroText = string.IsNullOrEmpty(uQuery.GetNode(n.Id).GetProperty("introText").Value) ? string.Empty : uQuery.GetNode(n.Id).GetProperty("introText").Value,
  Image = ImageCheck(uQuery.GetNode(n.Id).GetProperty("smallImage").Value)

}).Distinct().ToList();