J'ai un Question en utilisant ces mêmes exemples - Cette question est axée sur un problème différent.
Compte tenu des classes suivantes: si J'ai besoin de être capable d'exécuter le prédicat sur une liste aplatie de la personne Comment puis-je obtenir la collection family.Person pour devenir une liste aplatie de personne? p> p> famille code> a une méthode définie comme telle: p>
code>. Dans l'exemple ci-dessus code> SelectMany code> n'atteint pas la liste comme je l'avais espéré. Ce qui précède ne sera pas compilé car le type inféré ne peut pas être déterminé. P>
5 Réponses :
family.person code> est déjà em> une liste aplatie; Il n'est pas nécessaire d'appeler
SelectMany code> dessus.
public IEnumerable<Person> Find (Func<Person, bool> predicate) {
return family.Person.Where(predicate);
}
Notez que la personne a une liste imbriquée
@Matt - Je n'ai totalement pas vu ça - surtout en considérant le code d'origine de l'OP de family.person.selectmany (p => p) code> je modifierais pour réparer, mais cela ressemble à des peines déjà frappés hors du parc
Vous n'avez pas besoin de SelectMany code> et
Rendement de rendement code> - Vous avez besoin de l'une ou de l'autre:
public IEnumerable<Person> Find (Func<Person, bool> predicate) {
return family.Person.Where(p => predicate(p)); // Can be written simply as Where(predicate)
}
'p => prédicat (p)' i> peut être réduit à juste "prédicat" i> - guichet automatique Vous enveloppez une Func
@Mattdavavey J'ai ajouté une enveloppe pour enlever la "magie" de l'expression. J'ai ajouté une ligne de commentaire pour dire que cela peut être simplifié. C'est juste que la recherche d'un où code> clause sans
=> code> est peut-être déroutant aux personnes ayant une expérience relativement peu linq.
ouais je pense que c'est une chose pertinente à faire :)
À ma connaissance, le moyen le plus simple d'accomplir est d'utiliser une aide.
public IEnumerable<Person> Find (Func<Person, bool> predicate) { var familyRoot = new Person() { People = family.Person }; return FlattenTree(familyRoot).Where(predicate); }
Merci! et merci! PS J'utilise ce modèle assez souvent que j'ai écrit une version générique en tant que méthode d'extension. Super utile.
SelectMany n'aplatit que un niveau de hiérarchie:
public IEnumerable<Person> Find(Func<Person, bool> predicate) { foreach(Person p in family.Person) { IEnumerable<Person> result = FindFromPerson(p); foreach(Person x in result) { yield return x; } } } public IEnumerable<Person> FindFromPerson(Person p, Func<Person, bool> predicate) { if predicate(p) { yield return p; } foreach(Person child in p.People) { IEnumerable<Person> childResults = FindFromPerson(child); foreach(Person x in childResults) { yield return x; } } }
public IEnumerable<Person> Find(IEnumerable<Person> input, Func<Person, bool> predicate) { return input.Select(p => { var thisLevel = new List<Person>(); if(predicate(p)) thisLevel.Add(p); return thisLevel.Union(Find(p.People ?? new List<Person>(), predicate)); } ).SelectMany(p => p); }
+1 Pour avoir repéré la structure de données récursive, la question ne faisait pas assez évident ce point :)
Je recommande Concat sur un syndicat car il n'est pas nécessaire de faire passer des doublons croisés.
Si vous avez des boucles dans votre structure de données, vous pouvez cette solution: Stackoverflow.com/Questions/141467/Recursive-list-Flatting / ...