Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

279
Views
¿Cómo iterar una colección entre dos elementos?

Considere, por ejemplo, una lista de objetos:

 List<MyClass> myList;

Tengo un método que pasa dos referencias a elementos dentro de la lista. Quiero iterar todos los elementos dentro de los dados (nota: no sé cuál de los dos elementos viene primero en la lista):

 privat void MyFunction(MyClass listItem, MyClass anotherListItem) { foreach(var item in ????) { // do something } }

Actualmente he resuelto este caso de uso de la siguiente manera:

 int listItemIdx = myList.IndexOf(listItem); int anotherListItemIdx = myList.IndexOf(anotherListItem); if(listItemIdx < anotherListItemIdx ) { for(int i = listItemIdx ; i <= anotherListItemIdx ; i++) { // do stuff } } else { for (int i = anotherListItemIdx ; i < listItemIdx ; i++) { // do stuff } }

Me preguntaba si hay una solución más elegante, eficiente o integrada para este problema.

over 4 years ago · Santiago Trujillo
5 answers
Answer question

0

¿Está ordenada la lista? Puede usar ese hecho para darse cuenta de qué elemento debe ser el primero. Sin embargo, puede hacerlo con un bucle for, si lo prefiere:

 private static void MyFunction(string item1, string item2) { List<string> input = new() {"A", "B", "C", "D", "E"}; int index1 = input.IndexOf(item1); int index2 = input.IndexOf(item2); int beginIndex = Math.Min(index1, index2); int count = Math.Abs(index1 - index2) + 1; foreach (string item in input.GetRange(beginIndex, count)) { Console.Write(item); } }
over 4 years ago · Santiago Trujillo Report

0

Itera tres veces sobre la lista: dos veces en IndexOf y luego una vez más en su bucle. Puede hacer que su código sea más eficiente con este código, que itera solo una vez en la lista.

 privat void MyFunction(MyClass listItem, MyClass anotherListItem) { bool betweenTwoItems = false; foreach(var item in myList) { if(item == listItem || item == anotherListItem) { betweenTwoItems = !betweenTwoItems; if(!betweenTwoItems) { break; } } if(betweenTwoItems ) { // do stuff } } }

Establecemos una variable bool si estamos entre los dos elementos. Al principio, es falso. Luego iteramos sobre la lista y verificamos si el elemento actual es uno de los dos parámetros del método. Si este es el caso, invertimos el valor del bool. Si tras la inversión del bool el valor es falso, podemos salir de la lista. Después de eso, verificamos si el bool es verdadero. Si es así, podemos hacer cosas.

Demostración en línea: https://dotnetfiddle.net/xYcr7V

over 4 years ago · Santiago Trujillo Report

0

Si está buscando rendimiento ( IndexOf dos veces puede ser un poco lento) y generalización (cuando myList no es necesario List<T> pero IEnumerable<T> solamente) puede ponerlo como

 bool proceed = false; MyClass lastItem = default; foreach (var item in myList) { if (!proceed) { if (proceed = item == listItem) lastItem = anotherListItem; else if (proceed = item == anotherListItem) lastItem = listItem; } if (proceed) { //TODO: do staff here if (item == lastItem) break; } }
over 4 years ago · Santiago Trujillo Report

0

Su solución existente se puede mejorar:

 int listItemIdx = myList.IndexOf(listItem); int anotherListItemIdx = myList.IndexOf(anotherListItem); int startIdx = Math.Min(listItemIdx, anotherListItemIdx); int endIdx = Math.Max(listItemIdx, anotherListItemIdx); for(int i = startIdx ; i <= endIdx ; i++) { // do stuff }

Por lo tanto, la duplicación de código desaparece y solo se requiere una refactorización menor.

Para crear una versión de bucle de rango, puede crear un subconjunto usando GetRange() , algo como:

 int listItemIdx = myList.IndexOf(listItem); int anotherListItemIdx = myList.IndexOf(anotherListItem); int startIdx = Math.Min(listItemIdx, anotherListItemIdx); int endIdx = Math.Max(listItemIdx, anotherListItemIdx); var subset = myList.GetRange(startIdx, endIdx - startIdx); foreach(var item in subset) { // do stuff }

Por lo tanto, filtrar la lista y procesar la lista ahora se pueden separar.

over 4 years ago · Santiago Trujillo Report

0

Versión más genérica de la misma idea. Entonces esto se puede crear como método de extensión para IEnumerable<,>

 public static IEnumerable<T> RangeOf<T>(this IEnumerable<T> elements, T el1, T el2, IEqualityComparer<T> comparer = null) { comparer ??= EqualityComparer<T>.Default; var hasStarted = false; var end = default; foreach (T el in elements) { if (!hasStarted) { hasStarted = comparer.Equals(el, el1) || comparer.Equals(el, el2); end = comparer.Equals(el, el1) ? el2 : el1; } if (hasStarted) yield return el; if (comparer.Equals(el, end)) yield break; } }

y la versión con el ciclo while admite rangos de el a el . Por ejemplo, para [5, 0, 1, 2, 0, 6] el rango [0, 0] será [0, 1, 2, 0] :

 public static IEnumerable<T> RangeOf<T>(this IEnumerable<T> elements, T el1, T el2, IEqualityComparer<T> comparer = null) { comparer ??= EqualityComparer<T>.Default; var hasStarted = false; var end = default; var it = elements.GetEnumerator(); while (!hasStarted && it.MoveNext()) { T el = it.Current; hasStarted = comparer.Equals(el , el1) || comparer.Equals(el , el2); end = comparer.Equals(it.Current, el1) ? el2 : el1; } if (hasStarted) yield return it.Current; while (it.MoveNext()) { yield return it.Current; if (comparer.Equals(it.Current, end)) yield break; } }

ambos se pueden usar así

 foreach (var el in list.RangeOf(listItem, anotherListItem)) // Do with el whatever you want to do
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!