web-dev-qa-db-fra.com

Liste unique d'éléments utilisant LINQ

J'utilise LINQ depuis un certain temps maintenant, mais semble être bloqué sur quelque chose en ce qui concerne les articles uniques, j'ai la liste suivante:

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

Cela a les propriétés suivantes: ID de chaîne, type de chaîne, description de chaîne, exemple:

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

Je souhaite avoir une requête LINQ qui regroupera les articles en stock par leur type et les renverra en tant que nouvelle liste de stock (elle doit être du même type que la liste de stock d'origine).

Exemples de données:

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

...

Ma requête Linq veut pouvoir retourner tous les appareils de cuisine par exemple.
Je transmettrais donc ceci en tant que "type" dans la requête et il retournerait les éléments 1, 3 et 4 de cet exemple de liste.

Cette liste retournée doit également être de type: List<Stock>.

Essentiellement, je veux une liste des éléments uniques par type, un peu comme une requête SQL Distinct, comment puis-je y parvenir dans LINQ?
Les solutions alternatives sont correctes mais doivent être uniquement du code client Silverlight/C #.

Une autre précision est que je ne peux pas non plus fournir le paramètre "Kitchen Appliance" et que je veux juste les uniques, par exemple. il y a.

20
RoguePlanetoid

Approche flexible

Utilisez GroupBy et ToDictionary pour créer un dictionnaire de List<Stock> valeurs saisies sur la propriété Type:

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

Ensuite, vous pouvez accéder aux types eux-mêmes ainsi qu'à une liste pour tout type donné assez facilement:

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

Cette approche prend vraiment soin de tous vos besoins, comme je le vois. Mais pour d'autres options, voir ci-dessous.

Approche alternative (rapide et sale)

Vous pouvez toujours simplement utiliser Where pour obtenir les éléments du type souhaité, puis ToList pour placer ces éléments dans un nouveau List<Stock>:

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

En réponse à cette dernière partie:

Une autre précision est que je ne peux pas non plus fournir le paramètre "Kitchen Appliance" et que je veux juste les uniques, par exemple. il y a.

Ici, vous semblez vouloir quelque chose de complètement différent: fondamentalement le comportement fourni par Distinct . Pour cette fonctionnalité, vous pouvez essentiellement utiliser réponse de Soonts (éventuellement, renvoyer un IEnumerable<tKey> au lieu de IEnumerable<tSource>), ou vous pouvez simplement utiliser Distinct en combinaison avec Select pour éviter d'avoir à implémenter un IEqualityComparer<Stock> (voir ci-dessous).


Mettre à jour

En réponse à votre clarification, voici ma recommandation: deux méthodes, une pour chaque objectif ( principe de responsabilité unique ):

// 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
Dan Tao

On dirait que c'est une simple clause Where nécessaire.

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

Si vous vouliez strictement le Types contenu dans la liste source:

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

4
p.campbell
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
Soonts
var kitchenAppliances = stocks.Where(stock => stock.Type == "Kitchen Appliance");
3
Martin Liversage

Vous pouvez également faire quelque chose dans ce sens, dans ce cas, je prends des résultats lucene puis je retire les nœuds parapluies à un type anonyme

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

Je ne comprends probablement pas la question, mais cela me semble être une requête Linq assez simple:

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

ou si vous préférez la syntaxe de la méthode d'extension:

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

Ce que je ne comprends pas, c'est votre utilisation de distinct et unique dans ce contexte. Les objets sont déjà uniques, et il me semble que vous souhaitez une requête basique "donnez-moi tous les appareils de cuisine".