findindex ejemplo c# .net-2.0 predicate

ejemplo - list find c#



Combinar mĂșltiples predicados (7)

En .NET 2.0, hay delegados anónimos que puede usar allí:

List<string> filteredNames = names.FindAll( delegate(string s) { return StartsWithE(s) OR StartsWithI(s); } );

De hecho, puede usarlo para reemplazar sus funciones también:

List<string> filteredNames = names.FindAll( delegate(string s) { return s.StartsWith("E") || s.StartsWith("I"); } );

¿Hay alguna manera en c # .NET 2.0! combinar múltiples predicados?

Digamos que tengo el siguiente código.

List<string> names = new List<string>(); names.Add("Jacob"); names.Add("Emma"); names.Add("Michael"); names.Add("Isabella"); names.Add("Ethan"); names.Add("Emily"); List<string> filteredNames = names.FindAll(StartsWithE); static bool StartsWithE(string s) { if (s.StartsWith("E")) { return true; } else { return false; } }

Esto me da:

Emma Ethan Emily

Así que esto es algo muy bueno, pero sé que quiero poder filtrar usando múltiples predicados.

Así que quiero poder decir algo como esto:

List<string> filteredNames = names.FindAll(StartsWithE OR StartsWithI);

Para obtener:

Emma Isabella Ethan Emily

¿Cómo puedo conseguir esto? Actualmente solo estoy filtrando la lista completa dos veces y luego estoy combinando los resultados. Pero desafortunadamente esto es bastante ineficiente y, lo que es más importante, pierdo el orden de clasificación original, lo cual no es aceptable en mi situación.

También necesito poder iterar sobre cualquier número de filtros / predicados ya que puede haber bastante.

Una vez más, debe ser una solución .NET 2.0 desafortunadamente, no puedo usar una versión más nueva del marco

Muchas gracias.


Habiendo usado este patrón extensivamente con el método de matriz ''params'' anterior, me intrigó saber recientemente sobre el delegado de multidifusión. Como los delegados soportan inherentemente una lista (o multidifusión), puede omitir el patrón params [] y simplemente proporcionar un solo delegado a su función Test (). Deberá llamar a GetInvokationList en el Predicado <> suministrado. Vea esto: Delegado de multidifusión de tipo Func (con valor de retorno)?


Podría crear un tercer predicado que internamente ORs los resultados juntos. Creo que podrías hacer esto sobre la marcha usando una expresión lambda. Algo como esto (esta no es una expresión lambda ya que no soy muy bueno con ese snytax):

static bool StartsWithEorI(string s) { return StartsWithE(s) || StartsWithI(s); }


Podría incluir el método de predicado en una clase y hacer que el constructor acepte una matriz de cadenas para probar:

class StartsWithPredicate { private string[] _startStrings; public StartsWithPredicate(params string[] startStrings) { _startStrings = startStrings; } public bool StartsWith(string s) { foreach (var test in _startStrings) { if (s.StartsWith(test)) { return true; } } return false; } }

Entonces puedes hacer una llamada como esta:

List<string> filtered = names.FindAll((new StartsWithPredicate("E", "I")).StartsWith);

De esa manera, puede probar cualquier combinación de cadenas de entrada sin necesidad de ampliar la base de código con nuevas variaciones del método StartsWith .


Qué tal si:

public static Predicate<T> Or<T>(params Predicate<T>[] predicates) { return delegate (T item) { foreach (Predicate<T> predicate in predicates) { if (predicate(item)) { return true; } } return false; }; }

Y para completar:

public static Predicate<T> And<T>(params Predicate<T>[] predicates) { return delegate (T item) { foreach (Predicate<T> predicate in predicates) { if (!predicate(item)) { return false; } } return true; }; }

Entonces llámalo con:

List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE, StartsWithI));

Otra alternativa sería usar delegados de multidifusión y luego dividirlos con GetInvocationList() , luego hacer lo mismo. Entonces podrías hacer:

List<string> filteredNames = names.FindAll(Helpers.Or(StartsWithE+StartsWithI));

Sin embargo, no soy un gran fanático de este último enfoque, se siente como un abuso de la multidifusión.


Recientemente se me ocurrió una solución similar a este problema, que también podría ser útil. Expandí el método FindAll para listas, permitiéndome apilar predicados en listas cuando lo necesitaba:

public static class ExtensionMethods { public static List<T> FindAll<T> (this List<T> list, List<Predicate<T>> predicates) { List<T> L = new List<T> (); foreach (T item in list) { foreach (Predicate<T> p in predicates) { if (!(p (item))) break; } L.Add (item); } return L; } }

Devuelve una lista con solo los elementos que coinciden con todos los predicados dados. Por supuesto, puede modificarse fácilmente a OR todos los predicados en lugar de AND. Pero con eso solo uno puede reunir una buena variedad de combinaciones lógicas.

Uso:

{ List<Predicate<int>> P = new List<Predicate<int>> (); P.Add (j => j > 100); P.Add (j => j % 5 == 0 || j % 7 == 0); P.Add (j => j < 1000); List<int> L = new List<int> () { 0, 1, 2, ... 999, 1000 } List<int> result = L.FindAll (P); // result will contain: 105, 110, 112, 115, 119, 120, ... 994, 995 }


Supongo que podrías escribir algo como esto:

Func<string, bool> predicate1 = s => s.StartsWith("E"); Func<string, bool> predicate2 = s => s.StartsWith("I"); Func<string, bool> combinedOr = s => (predicate1(s) || predicate2(s)); Func<string, bool> combinedAnd = s => (predicate1(s) && predicate2(s));

... y así.