2009-02-15 9 views
4

J'ai un problème intéressant, et je n'arrive pas à comprendre l'expression lambda pour que cela fonctionne.Utilisation d'expressions lambda pour obtenir un sous-ensemble où les éléments du tableau sont égaux

J'ai le code suivant:

List<string[]> list = GetSomeData(); // Returns large number of string[]'s 
List<string[]> list2 = GetSomeData2(); // similar data, but smaller subset 
&nbsp; 
List<string[]> newList = list.FindAll(predicate(string[] line){ 
    return (???); 
}); 

Je veux retourner uniquement les enregistrements dans la liste où l'élément 0 de chaque chaîne [] est égale à l'un des éléments 0 dans liste2.

liste

contient des données comme ceci:

"000", "Data", "more data", "etc..." 

liste2 contient des données comme ceci:

"000", "different data", "even more different data" 

Au fond, je pourrais écrire ce code comme ceci:

List<string[]> newList = new List<string[]>(); 
foreach(var e in list) 
{ 
    foreach(var e2 in list2) 
    { 
     if (e[0] == e2[0]) 
      newList.Add(e); 
    } 
} 
return newList; 

Mais, je J'essaie d'utiliser des génériques et plus de lambda, donc je suis à la recherche d'une bonne solution propre. Celui-ci me frustrant cependant .. peut-être une trouvaille dans une trouvaille?

EDIT: réponse de Marc ci-dessous me conduire à expérimenter avec un varation qui ressemble à ceci:

var z = list.Where(x => list2.Select(y => y[0]).Contains(x[0])).ToList(); 

Je ne sais pas comment ce efficent est, mais il fonctionne et est suffisamment succincte. Quelqu'un d'autre a des suggestions?

Répondre

10

Vous pourriez rejoindre? J'utiliser deux pas moi-même, bien que:

var keys = new HashSet<string>(list2.Select(x => x[0])); 
var data = list.Where(x => keys.Contains(x[0])); 

Si vous avez seulement .NET 2.0, puis installez LINQBridge et utilisez ce qui précède (ou similaire avec un Dictionary<> si LINQBridge ne comprend pas HashSet<>), ou peut-être utiliser imbriqué Find:

var data = list.FindAll(arr => list2.Find(arr2 => arr2[0] == arr[0]) != null); 

noter cependant que l'approche Find est O (n * m), où, comme l'approche HashSet<> est O (n + m) ...

+0

Quelle est la raison du HashSet? Il semble bien fonctionner sans l'ensemble a (voir mon édition ci-dessus). Est-ce que le HashSet le rend plus efficace? –

+0

note; Pour les très petites listes, il peut être plus efficace de simplement balayer la liste [comme le fait votre édition] ... mais pour les petites listes, il sera très rapide, quelle que soit l'approche utilisée. À mesure que la taille de la liste augmente, l'approche d'analyse peut rapidement devenir un goulot d'étranglement. –

+0

Ok. Un élément d'information que je devrais mentionner est que les "clés" (ou list2) seront toujours relativement petites, probablement moins de 10. Alors que la source (liste) peut être plusieurs centaines d'éléments (jusqu'à 1000). –

3

Vous pouvez utiliser l'Intersect extensio n méthode dans System.Linq, mais vous devrez fournir un IEqualityComparer pour faire le travail.

static void Main(string[] args) 
    { 
     List<string[]> data1 = new List<string[]>(); 
     List<string[]> data2 = new List<string[]>(); 

     var result = data1.Intersect(data2, new Comparer()); 
    } 

    class Comparer : IEqualityComparer<string[]> 
    { 
     #region IEqualityComparer<string[]> Members 

     bool IEqualityComparer<string[]>.Equals(string[] x, string[] y) 
     { 
      return x[0] == y[0]; 
     } 

     int IEqualityComparer<string[]>.GetHashCode(string[] obj) 
     { 
      return obj.GetHashCode(); 
     } 

     #endregion 
    } 
+0

solution intéressante, mais il est plus grand que le problème d'origine;) –

+0

Cela dépend vraiment du contexte. Si cela revient plusieurs fois, placez votre comparateur d'égalité dans un assemblage de bibliothèque et vous pouvez utiliser un simple appel à Intersection pour obtenir l'intersection de vos deux listes. Plus tard si vous avez besoin, vous pouvez utiliser le même comparateur pour égal, ou Except, ou d'autres utilisations –

0

Intersect peut fonctionner pour vous. Intersect recherche tous les éléments figurant dans les deux listes. Ok, relisez la question. Intersect ne prend pas la commande en compte. J'ai écrit une expression linq légèrement plus complexe qui retournera une liste d'éléments qui sont dans la même position (index) avec la même valeur.

List<String> list1 = new List<String>() {"000","33", "22", "11", "111"}; 
List<String> list2 = new List<String>() {"000", "22", "33", "11"}; 

List<String> subList = list1.Select ((value, index) => new { Value = value, Index = index}) 
      .Where(w => list2.Skip(w.Index).FirstOrDefault() == w.Value) 
      .Select (s => s.Value).ToList(); 


Result: {"000", "11"} 

Explication de la requête:

Sélectionnez un ensemble de valeurs et de la position de cette valeur.

Filtre défini lorsque l'élément à la même position dans la deuxième liste a la même valeur.

Sélectionnez simplement la valeur (pas l'index également).

Note J'ai utilisé: list2.Skip(w.Index).FirstOrDefault() //instead of list2[w.Index] Afin qu'il gère des listes de différentes longueurs.

Si vous savez que les listes auront la même longueur ou liste1 sera toujours plus courte, alors list2[w.Index] serait probablement un peu plus rapide.

Questions connexes