visual valid name method example comment c# java ruby loops foreach

valid - params comments c#



Identificación del último ciclo cuando se usa para cada (25)

¿Es esto lo suficientemente elegante? Asume una lista no vacía.

list[0,list.length-1].each{|i| puts "Looping:"+i # if not last loop iteration } puts "Last one:" + list[list.length-1]

Quiero hacer algo diferente con la última iteración de bucle al realizar ''foreach'' en un objeto. Estoy usando Ruby, pero lo mismo aplica para C #, Java, etc.

list = [''A'',''B'',''C''] list.each{|i| puts "Looping: "+i # if not last loop iteration puts "Last one: "+i # if last loop iteration }

La salida deseada es equivalente a:

Looping: ''A'' Looping: ''B'' Last one: ''C''

La solución obvia es migrar el código a un bucle for utilizando ''for i in 1..list.length'' , pero para cada solución se siente más elegante. ¿Cuál es la forma más elegante de codificar un caso especial durante un ciclo? ¿Se puede hacer con foreach?


¿Qué tal obtener primero una referencia al último elemento y luego usarlo para comparar dentro del ciclo foreach? No digo que debas hacer esto ya que yo mismo usaría el ciclo basado en índice mencionado por KlauseMeier . ¡Y lo siento, no conozco a Ruby, así que la siguiente muestra está en C #! Espero que no te importe :-)

string lastItem = list[list.Count - 1]; foreach (string item in list) { if (item != lastItem) Console.WriteLine("Looping: " + item); else Console.Writeline("Lastone: " + item); }

Revisé el siguiente código para comparar por referencia, no por valor (solo puedo usar tipos de referencia, no tipos de valores). el siguiente código debería admitir múltiples objetos que contengan la misma cadena (pero no el mismo objeto de cadena) ya que el ejemplo de MattChurcy no especificó que las cadenas deben ser distintas y utilicé el último método de LINQ en lugar de calcular el índice.

string lastItem = list.Last(); foreach (string item in list) { if (!object.ReferenceEquals(item, lastItem)) Console.WriteLine("Looping: " + item); else Console.WriteLine("Lastone: " + item); }

Limitaciones del código anterior. (1) Solo puede funcionar para cadenas o tipos de referencia, no tipos de valores. (2) El mismo objeto solo puede aparecer una vez en la lista. Puede tener diferentes objetos que contienen el mismo contenido. Las cadenas literales no se pueden usar repetidamente ya que C # no crea un objeto único para las cadenas que tienen el mismo contenido.

Y yo no soy estúpido. Sé que un bucle basado en índice es el que se debe usar. Ya lo dije cuando publiqué la respuesta inicial. Proporcioné la mejor respuesta que puedo en el contexto de la pregunta. Estoy demasiado cansado para seguir explicando esto, ¿pueden votar para eliminar mi respuesta? Estaré tan feliz si esta se va. Gracias


¿Que tal este? Acabo de aprender un poco de Ruby. jejeje

list.collect {|x|(x!=list.last ? "Looping:"+x:"Lastone:"+x) }.each{|i|puts i}


¿Sería una solución viable para su caso simplemente sacar los primeros / últimos elementos de su matriz antes de hacer el "general" de cada carrera?

Me gusta esto:

list = [''A'',''B'',''C'',''D''] first = list.shift last = list.pop puts "First one: #{first}" list.each{|i| puts "Looping: "+i } puts "Last one: #{last}"


Al menos en C # eso no es posible sin un bucle for regular.

El enumerador de la colección decide si existe un próximo elemento (método MoveNext), el ciclo no lo sabe.


Creo que prefiero la solución de kgiannakakis , sin embargo, siempre puedes hacer algo como esto;

list = [''A'',''B'',''C''] list.each { |i| if (i != list.last) puts "Looping:#{i}" else puts "Last one:#{i}" end }


Debería usar foreach solo si maneja cada uno de la misma manera. Use interación basada en índices en su lugar. De lo contrario, debe agregar una estructura diferente alrededor de los elementos, que puede usar para diferenciar la normal de la anterior en la llamada de foreach (consulte los buenos documentos acerca del mapa, que se redujeron de google para el fondo: http://labs.google.com/papers/mapreduce.html , map == foreach, reducido == por ejemplo, suma o filtro).

El mapa no tiene conocimiento de la estructura (especialmente la posición de un elemento), solo transforma un elemento por elemento (¡ningún conocimiento de un elemento puede usarse para transformar otro!), Pero reduce puede usar una memoria para, por ejemplo, contar la posición y manejar el último elemento.

Un truco común es invertir la lista y manejar la primera (que ahora tiene un índice conocido = 0) y luego aplicar nuevamente el reverso. (Que es elegante pero no rápido;))


El constructo foreach (en Java definitivamente, probablemente también en otros idiomas) pretende representar el tipo más general de iteración, que incluye iteración sobre colecciones que no tienen un orden de iteración significativo. Por ejemplo, un conjunto basado en hash no tiene un orden, y por lo tanto no hay un "último elemento". La última iteración puede arrojar un elemento diferente cada vez que itera.

Básicamente: no, la construcción foreach no debe usarse de esa manera.


Elimine el último de la lista y conserve su avlue.

Spec spec = specs.Find(s=>s.Value == ''C''); if (spec != null) { specs.Remove(spec); } foreach(Spec spec in specs) { }


En Ruby usaría each_with_index en esta situación

list = [''A'',''B'',''C''] last = list.length-1 list.each_with_index{|i,index| if index == last puts "Last one: "+i else puts "Looping: "+i # if not last loop iteration end }


Este problema se puede resolver de una manera elegante usando la coincidencia de patrones en un lenguaje de programación funcional como F #:

let rec printList (ls:string list) = match ls with | [last] -> "Last " + last | head::rest -> "Looping " + head + "/n" + printList (rest) | [] -> ""


Foreach es elegante, ya que no se preocupa por la cantidad de elementos en una lista y trata a cada elemento por igual, creo que su única solución será usar un bucle for que se detenga en itemcount-1 y luego presente su último elemento fuera de el bucle o un condicional dentro del bucle que maneja esa condición específica, es decir, si (i == itemcount) {...} else {...}


Lo que estás tratando de hacer parece demasiado avanzado para el ciclo foreach. Sin embargo, puede usar Iterator s explícitamente. Por ejemplo, en Java, escribiría esto:

Collection<String> ss = Arrays.asList("A","B","C"); Iterator<String> it = ss.iterator(); while (it.hasNext()) { String s = it.next(); if(it.hasNext()) System.out.println("Looping: " + s); else System.out.println("Last one: " + s); }


No sé cómo: cada bucle funciona en otros idiomas, pero java. En Java for-each usa la interfaz Iterable que usa for-each para obtener un iterador y un bucle con él. Iterator tiene un método hasNext que podría usar si pudiera ver el iterador dentro del ciclo. De hecho, puede hacer el truco encerrando un Iterator ya obtenido en un objeto Iterable para que el bucle for obtenga lo que necesita y pueda obtener un método hasNext dentro del bucle.

List<X> list = ... final Iterator<X> it = list.iterator(); Iterable<X> itw = new Iterable<X>(){ public Iterator<X> iterator () { return it; } } for (X x: itw) { doSomething(x); if (!it.hasNext()) { doSomethingElse(x); } }

Puedes crear una clase que envuelva todo este material iterable e iterador para que el código se vea así:

IterableIterator<X> itt = new IterableIterator<X>(list); for (X x: itit) { doSomething(x); if (!itit.hasNext()) { doSomethingElse(x); } }


Noto que varias sugerencias asumen que puede encontrar el último elemento de la lista antes de comenzar el ciclo, y luego compara cada elemento con este elemento. Si puede hacer esto de manera eficiente, entonces la estructura de datos subyacente probablemente sea una matriz simple. Si ese es el caso, ¿por qué molestarse con el foreach en absoluto? Solo escribe:

for (int x=0;x<list.size()-1;++x) { System.out.println("Looping: "+list.get(x)); } System.out.println("Last one: "+list.get(list.size()-1));

Si no puede recuperar un elemento de una posición arbitraria de manera eficiente, como si la estructura subyacente fuera una lista vinculada, entonces obtener el último elemento probablemente implique una búsqueda secuencial de toda la lista. Dependiendo del tamaño de la lista, puede ser un problema de rendimiento. Si se trata de una función que se ejecuta con frecuencia, es posible que desee considerar el uso de una matriz o ArrayList o una estructura comparable para que pueda hacerlo de esta manera.

Me parece que me pregunta: "¿Cuál es la mejor manera de poner un tornillo usando un martillo?", Cuando, por supuesto, la mejor pregunta es: "¿Cuál es la herramienta correcta para poner un tornillo?"


Otro patrón que funciona, sin tener que volver a escribir el ciclo foreach :

var delayed = null; foreach (var X in collection) { if (delayed != null) { puts("Looping"); // Use delayed } delayed = X; } puts("Last one"); // Use delayed

De esta forma, el compilador mantiene el ciclo en línea recta, los iteradores (incluidos aquellos sin conteos) funcionan como se espera, y el último se separa de los demás.

También uso este patrón cuando quiero que ocurra algo entre iteraciones, pero no después de la última. En ese caso, X se usa normalmente, el delayed refiere a otra cosa, y el uso del retraso solo comienza en el ciclo y no es necesario hacer nada después de que termine el ciclo.


Podrías hacer algo como eso (C #):

string previous = null; foreach(string item in list) { if (previous != null) Console.WriteLine("Looping : {0}", previous); previous = item; } if (previous != null) Console.WriteLine("Last one : {0}", previous);


Puede definir un método eachwithlast en su clase para hacer lo mismo que each en todos los elementos, pero el último, pero algo más para el último:

class MyColl def eachwithlast for i in 0...(size-1) yield(self[i], false) end yield(self[size-1], true) end end

Entonces podrías llamarlo así (por ser una instancia de MyColl o una subclase del mismo):

foo.eachwithlast do |value, last| if last puts "Last one: "+value else puts "Looping: "+value end end

Editar: siguiendo la sugerencia de molf:

class MyColl def eachwithlast (defaultAction, lastAction) for i in 0...(size-1) defaultAction.call(self[i]) end lastAction.call(self[size-1]) end end foo.eachwithlast( lambda { |x| puts "looping "+x }, lambda { |x| puts "last "+x } )


Ruby también tiene el método each_index:

list = [''A'',''B'',''C''] list.each_index{|i| if i < list.size - 1 puts "Looping:"+list[i] else puts "Last one:"+list[i] }

EDITAR:

O usando cada una (solución corregida de TomatoGG y Kirschstein):

list = [''A'', ''B'', ''C'', ''A''] list.each { |i| if (i.object_id != list.last.object_id) puts "Looping:#{i}" else puts "Last one:#{i}" end } Looping:A Looping:B Looping:C Last one:A

O

list = [''A'', ''B'', ''C'', ''A''] list.each {|i| i.object_id != list.last.object_id ? puts "Looping:#{i}" : puts "Last one:#{i}" }


Si está utilizando una colección que expone una propiedad Count , una suposición hecha por muchas de las otras respuestas, entonces también lo haré , entonces puede hacer algo como esto usando C # y LINQ:

foreach (var item in list.Select((x, i) => new { Val = x, Pos = i })) { Console.Write(item.Pos == (list.Count - 1) ? "Last one: " : "Looping: "); Console.WriteLine(item.Val); }

Si adicionalmente suponemos que se puede acceder directamente a los elementos en la colección por índice, la respuesta aceptada actualmente asume esto , entonces un ciclo de for simple será más elegante / legible que un foreach :

for (int i = 0; i < list.Count; i++) { Console.Write(i == (list.Count - 1) ? "Last one: " : "Looping: "); Console.WriteLine(list[i]); }

Si la colección no expone una propiedad Count y no se puede acceder por índice, entonces no hay realmente ninguna manera elegante de hacerlo, al menos no en C #. Una variación fija de errores de la respuesta de Thomas Levesque es probablemente lo más cercano que obtendrás.

Aquí está la versión corregida de errores de la respuesta de Thomas :

string previous = null; bool isFirst = true; foreach (var item in list) { if (!isFirst) { Console.WriteLine("Looping: " + previous); } previous = item; isFirst = false; } if (!isFirst) { Console.WriteLine("Last one: " + previous); }

Y así es como lo haría en C # si la colección no expone una propiedad Count y el índice no puede acceder directamente a los elementos. (Tenga en cuenta que no hay ningún foreach y que el código no es particularmente conciso, pero dará un rendimiento decente en casi cualquier colección enumerable).

// i''m assuming the non-generic IEnumerable in this code // wrap the enumerator in a "using" block if dealing with IEnumerable<T> var e = list.GetEnumerator(); if (e.MoveNext()) { var item = e.Current; while (e.MoveNext()) { Console.WriteLine("Looping: " + item); item = e.Current; } Console.WriteLine("Last one: " + item); }


Similar a la respuesta de kgiannakakis:

list.first(list.size - 1).each { |i| puts "Looping: " + i } puts "Last one: " + list.last


Use join siempre que sea posible.

Muy a menudo, el delimitador es el mismo entre todos los elementos, simplemente únelos junto con la función correspondiente en su idioma.

Ruby ejemplo,

puts array.join(", ")

Esto debería cubrir el 99% de todos los casos, y si no se divide la matriz en la cabeza y la cola.

Ruby ejemplo,

*head, tail = array head.each { |each| put "looping: " << each } puts "last element: " << tail


Veo un código complejo y poco legible aquí ... ¿por qué no mantenerlo simple?

var count = list.Length; foreach(var item in list) if (--count > 0) Console.WriteLine("Looping: " + item); else Console.Writeline("Lastone: " + item);

¡Es solo una declaración extra!

Otra situación común es que desea hacer algo extra o menos con el último elemento, como colocar un separador entre los elementos:

var count = list.Length; foreach(var item in list) { Console.Write(item); if (--count > 0) Console.Write(","); }


<hello> ¿qué estamos pensando aquí?

public static void main(String[] args) { // TODO Auto-generated method stub String str = readIndex(); String comp[] = str.split("}"); StringBuffer sb = new StringBuffer(); for (String s : comp) { sb.append(s); sb.append("}/n"); } System.out.println (sb.toString()); }

Como una notación de modelado, la influencia de la notación OMT domina (por ejemplo, el uso de rectángulos para clases y objetos). Aunque se eliminó la notación de Booch "nube", se abrazó la capacidad de Booch para especificar detalles de diseño de nivel inferior. La notación de caso de uso de Objectory y la notación de componentes de Booch se integraron con el resto de la notación, pero la integración semántica fue relativamente débil en UML 1.1, y no se corrigió realmente hasta la revisión principal de UML 2.0.


C # 3.0 o más nuevo

En primer lugar, escribiría un método de extensión:

public static void ForEachEx<T>(this IEnumerable<T> s, Action<T, bool> act) { IEnumerator<T> curr = s.GetEnumerator(); if (curr.MoveNext()) { bool last; while (true) { T item = curr.Current; last = !curr.MoveNext(); act(item, last); if (last) break; } } }

Entonces, usar el nuevo foreach es muy simple:

int[] lData = new int[] { 1, 2, 3, 5, -1}; void Run() { lData.ForEachEx((el, last) => { if (last) Console.Write("last one: "); Console.WriteLine(el); }); }