2010-07-27 4 views
2

J'ai 2 listes. Je veux comparer chaque élément avec chaque élément pour les deux listes en utilisant LINQ (par opposition à utiliser une boucle imbriquée). Mais, le Contient ne répond pas à mes besoins parce que j'ai besoin de faire une comparaison personnalisée. J'imagine un comparateur personnalisé est ce dont j'ai besoin mais pas sûr à 100%.Linq personnalisé contient-il?

Je ne pense pas que cela devrait être trop difficile, mais je ne sais pas exactement l'outil dont j'ai besoin pour cela. Les deux listes contiennent toutes deux des types d'objets distincts et différents.

Mise à jour:

Désolé, si je n'étais pas claire. J'ai 2 listes (ou enumerables) que je pouvais faire quelque chose comme ceci:

foreach(item i in list1) 
    foreach(otherItemType in List2) 
    { 
    if (CompareItem(x)) do something; 
    } 

Ce que je veux faire quelque chose comme ceci:

var matches = myList1.Where(t => myList2.Something(t)) 

où quelque chose est un comparateur personnalisé, je peux peut-être passer outre la comparaison égale? Je pourrais utiliser le .Contains mais j'ai besoin de faire ma propre logique de comparaison.

Mise à jour: J'ai pensé à utiliser le IEqualityComparer mais il est configuré pour prendre les types de T, T et T, Y. Il peut y avoir certaines contraintes génériques que je pourrais utiliser pour résoudre ce problème. J'ai senti que cela devrait être facile/simple.

+0

Pouvez-vous expliquer vos besoins plus ou fournir un exemple données et résultats attendus? – LukeH

+0

Remplacez GetHashCode() de sorte que différents éléments renvoient différents codes de hachage, et que les éléments 'identiques' renvoient le même code de hachage. Ensuite, ça va fonctionner comme il se doit (je pense) – PostMan

+0

@PostMan - vous ne devriez jamais compter sur GetHashCode() retournant des valeurs différentes pour différents items, seulement qu'il retournera toujours la même valeur pour les items considérés égaux. –

Répondre

2
var matches = myList1.SelectMany(
    t1 => myList2.Where(
     t2 => t2.Something(t1) 
    ) 
); 

Le Where interne est comme la boucle foreach intérieure, et la SelectMany jointures externes les résultats après une itération dans la boucle comme dans foreach externe.

Vous pouvez faire une fonction pour le faire pour vous (non testé, ne peut pas rappeler la syntaxe d'extension):

public static IEnumerable<T2> MultiCompare<T1, T2>(this IEnumerable<T1> first, IEnumerable<T2> second, Func<bool, T1, T2> comparer) { 
    return first.SelectMany(
     t1 => second.Where(
      t2 => comparer(t1, t2) 
     ) 
    ); 
} 
+0

Merci. Y a-t-il une façon de faire cela plus claire? Ceci est légèrement difficile à lire mais semble fonctionner. –

+0

@Curtis White, Eh bien, vous pouvez faire une fonction, comme je viens de poster. – strager

+0

La syntaxe de l'extension devrait être '... MultiCompare (ce IEnumerable d'abord, ...' then 'first.SelectMany (...' – Jamiec

0

J'avais la question here il y a un moment qui pourrait vous aider à démarrer.

1

Si je comprends bien votre question, l'exemple ci-dessous fera. Depuis Tout prend un délégué, vous pouvez définir une comparaison de correspondance arbitraire entre les deux éléments de la liste. Si vous avez besoin de tous les éléments pour correspondre, utilisez Tous à la place de Tout.

[Test] 
public void StackOverflow() 
{ 
    var digits = new int[] {1, 2, 4, 9}; 
    var strings = new string[] {"1", "4", "5", "7"}; 

    var matches = strings.Where(s => digits.Any(d => d.ToString() == s)).ToList(); 

    // Prints 
    // 1 
    // 4 

    matches.ForEach(x => System.Diagnostics.Debug.WriteLine(x)); 
} 
1

Comment utiliser Enumerable.Join?

var list = new List<int> { 1, 2, 3, 4, 5 }; 
var list2 = new List<string> { "2", "4", "5" }; 

var matches = from i in list 
       join s in list2 on i.ToString() equals s 
       select i; // if you want to use the matching items from the 1st list 

// there's no ForEach on Enumerable so you'd have to write the extension yourself (which is easy) 
// or you could just output matches to a List first 
matches.ToList().ForEach(i => Console.WriteLine(i)); 

En ce qui concerne les jointures je préfère fortement la syntaxe de requête LINQ, mais vous pouvez également utiliser l'expression Lambda ils regardent généralement un peu en désordre ...

Questions connexes