Уникальный список объектов с помощью LINQ

Я использовал LINQ некоторое время теперь, но, кажется, застреваю на чем-то относительно Уникальных объектов, у меня есть список folling:

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

Это имеет следующие Свойства: идентификатор строки, строковый тип, представляет в виде строки Описание, пример:

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

Я хочу иметь запрос LINQ, который сгруппирует объекты в Stock их Типом и возвратит это как новый Список Stock (это должен быть тот же тип как исходный Список Stock).

Данные в качестве примера:

 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 Отличный запрос, как я достигаю этого в LINQ?
Альтернативные решения прекрасны, но должны быть Silverlight / клиентский код C# только.

Просто другое разъяснение состоит в том, что я также не могу предоставить параметру "Кухонный прибор" и могу просто хотеть уникальные, например, Он возвратил бы Кухонный прибор и Гостиную однажды каждый только, чтобы отчасти любить категорию, неважно, сколько из того Типа существует.

20
задан RoguePlanetoid 6 July 2010 в 14:12
поделиться

5 ответов

Гибкий подход

Используйте GroupBy и ToDictionary , чтобы создать словарь значений List , введенных на Свойство типа :

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"];

Этот подход действительно заботится обо всех ваших потребностях, как я его вижу. Но о некоторых других вариантах см. Ниже.

Альтернативный (быстрый и грязный) подход

Вы всегда можете просто использовать Где , чтобы получить элементы нужного вам типа, затем ToList , чтобы поместить эти элементы в новый Список :

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

В ответ на эту последнюю часть:

Еще одно уточнение: я также может не предоставлять параметр «Техника для кухни» а может просто захотеть уникальные, например, Это было бы вернуть бытовую технику и быт Комната по одному разу только для того, чтобы категория независимо от того, сколько из них Типа есть.

Здесь, похоже, вы хотите чего-то совершенно другого: в основном поведения, обеспечиваемого Distinct . Для этой функциональности вы можете использовать ответ Soonts (необязательно, возвращая IEnumerable вместо IEnumerable ), либо вы можете просто использовать Distinct в сочетании с Выберите , чтобы избежать необходимости реализации IEqualityComparer (см. ниже).


Обновление

В ответ на ваше разъяснение, вот моя рекомендация: два метода, по одному для каждой цели ( Принцип единой ответственности ):

// 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();
}
45
ответ дан 29 November 2019 в 23:00
поделиться
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
ответ дан 29 November 2019 в 23:00
поделиться

Я, вероятно, не понимаю вопроса, но для меня это звучит как довольно простой 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();

What I не понимаю, является ли ваше использование отличным и уникальным в этом контексте. Объекты уже уникальны, и мне кажется, что вам нужен базовый запрос «дайте мне всю кухонную технику».

1
ответ дан 29 November 2019 в 23:00
поделиться

Похоже, что нужно простое предложение 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();

4
ответ дан 29 November 2019 в 23:00
поделиться
var kitchenAppliances = stocks.Where(stock => stock.Type == "Kitchen Appliance");
3
ответ дан 29 November 2019 в 23:00
поделиться
Другие вопросы по тегам:

Похожие вопросы: