while sentencia repetitiva for ejemplos ciclo bucle java loops for-loop foreach

java - ejemplos - sentencia repetitiva for



¿Hay alguna forma de acceder a un contador de iteraciones en el bucle de Java para cada bucle? (14)

Solución idiomática:

final Set<Double> doubles; // boilerplate final Iterator<Double> iterator = doubles.iterator(); for (int ordinal = 0; iterator.hasNext(); ordinal++) { System.out.printf("%d:%f",ordinal,iterator.next()); System.out.println(); }

esta es en realidad la solución que Google sugiere en la discusión de Guava sobre por qué no proporcionaron un CountingIterator .

¿Hay alguna manera en el bucle de Java para cada uno?

for(String s : stringArray) { doSomethingWith(s); }

¿Para saber con qué frecuencia ya se ha procesado el bucle?

Aparte de usar el bucle antiguo y conocido for(int i=0; i < boundary; i++) - es el constructo

int i = 0; for(String s : stringArray) { doSomethingWith(s); i++; }

¿La única manera de tener dicho contador disponible en un bucle para cada uno?


Descubrí que el uso de un bucle for simple con un índice incremental era la solución más eficiente y confiable, como se publica aquí: https://.com/a/3431543/2430549


El uso de lambdas e interfaces funcionales en Java 8 hace posible la creación de nuevas abstracciones de bucle. Puedo recorrer una colección con el índice y el tamaño de la colección:

List<String> strings = Arrays.asList("one", "two","three","four"); forEach(strings, (x, i, n) -> System.out.println("" + (i+1) + "/"+n+": " + x));

Qué salidas:

1/4: one 2/4: two 3/4: three 4/4: four

Que implementé como:

@FunctionalInterface public interface LoopWithIndexAndSizeConsumer<T> { void accept(T t, int i, int n); } public static <T> void forEach(Collection<T> collection, LoopWithIndexAndSizeConsumer<T> consumer) { int index = 0; for (T object : collection){ consumer.accept(object, index++, collection.size()); } }

Las posibilidades son infinitas. Por ejemplo, creo una abstracción que usa una función especial solo para el primer elemento:

forEachHeadTail(strings, (head) -> System.out.print(head), (tail) -> System.out.print(","+tail));

Que imprime una lista separada por comas correctamente:

one,two,three,four

Que implementé como:

public static <T> void forEachHeadTail(Collection<T> collection, Consumer<T> headFunc, Consumer<T> tailFunc) { int index = 0; for (T object : collection){ if (index++ == 0){ headFunc.accept(object); } else{ tailFunc.accept(object); } } }

Las bibliotecas comenzarán a aparecer para hacer este tipo de cosas, o puedes rodar las tuyas.


Estoy un poco sorprendido de que nadie sugiera lo siguiente (admito que es un enfoque perezoso ...); Si stringArray es una lista de algún tipo, podría usar algo como stringArray.indexOf (S) para devolver un valor para el recuento actual.

Nota: esto supone que los elementos de la Lista son únicos, o que no importa si no son únicos (porque en ese caso devolverá el índice de la primera copia encontrada).

Hay situaciones en las que eso sería suficiente ...


Hay otra manera.

Dado que escribe su propia clase de Index y un método estático que devuelve un Iterable sobre instancias de esta clase, puede

for (Index<String> each: With.index(stringArray)) { each.value; each.index; ... }

Donde la implementación de With.index es algo como

class With { public static <T> Iterable<Index<T>> index(final T[] array) { return new Iterable<Index<T>>() { public Iterator<Index<T>> iterator() { return new Iterator<Index<T>>() { index = 0; public boolean hasNext() { return index < array.size } public Index<T> next() { return new Index(array[index], index++); } ... } } } } }


Hay una "variante" para la respuesta de pax ... ;-)

int i = -1; for(String s : stringArray) { doSomethingWith(s, ++i); }


Java 8 introdujo el Iterable#forEach() / Map#forEach() , que es más eficiente para muchas implementaciones de Collection / Map comparación con el "clásico" para cada bucle. Sin embargo, también en este caso no se proporciona un índice. El truco aquí es usar AtomicInteger fuera de la expresión lambda. Nota: las variables utilizadas dentro de la expresión lambda deben ser efectivamente finales, es por eso que no podemos usar un int ordinario.

final AtomicInteger indexHolder = new AtomicInteger(); map.forEach((k, v) -> { final int index = indexHolder.getAndIncrement(); // use the index });


La solución más sencilla es ejecutar su propio contador de esta manera:

int i = 0; for (String s : stringArray) { doSomethingWith(s, i); i++; }

El motivo de esto es que no hay una garantía real de que los elementos de una colección (de los que se haya ido esa variante for iteraciones) tengan un índice, o que tengan un orden definido (algunas colecciones pueden cambiar el orden cuando agrega o elimina elementos).

Vea por ejemplo, el siguiente código:

import java.util.*; public class TestApp { public static void AddAndDump(AbstractSet<String> set, String str) { System.out.println("Adding [" + str + "]"); set.add(str); int i = 0; for(String s : set) { System.out.println(" " + i + ": " + s); i++; } } public static void main(String[] args) { AbstractSet<String> coll = new HashSet<String>(); AddAndDump(coll, "Hello"); AddAndDump(coll, "My"); AddAndDump(coll, "Name"); AddAndDump(coll, "Is"); AddAndDump(coll, "Pax"); } }

Cuando ejecutas eso, puedes ver algo como:

Adding [Hello] 0: Hello Adding [My] 0: Hello 1: My Adding [Name] 0: Hello 1: My 2: Name Adding [Is] 0: Hello 1: Is 2: My 3: Name Adding [Pax] 0: Hello 1: Pax 2: Is 3: My 4: Name

lo que indica que, con razón, el orden no se considera una característica destacada de un conjunto.

Hay otras formas de hacerlo sin un contador manual, pero es un poco de trabajo para un beneficio dudoso.


Me temo que esto no es posible con foreach . Pero puedo sugerirte un simple estilo antiguo para bucles :

List<String> l = new ArrayList<String>(); l.add("a"); l.add("b"); l.add("c"); l.add("d"); // the array String[] array = new String[l.size()]; for(ListIterator<String> it =l.listIterator(); it.hasNext() ;) { array[it.nextIndex()] = it.next(); }

Tenga en cuenta que la interfaz de la List le da acceso a it.nextIndex() .

(editar)

A tu ejemplo cambiado:

for(ListIterator<String> it =l.listIterator(); it.hasNext() ;) { int i = it.nextIndex(); doSomethingWith(it.next(), i); }


No, pero puedes proporcionar tu propio contador.

La razón de esto es que el bucle for-each internamente no tiene un contador; se basa en la interfaz de Iterable , es decir, utiliza un Iterator para recorrer la "colección", que puede no ser una colección y, de hecho, puede ser algo que no se basa en índices (como una lista enlazada).


Para situaciones en las que solo necesito el índice de vez en cuando, como en una cláusula catch, a veces usaré indexOf.

for(String s : stringArray) { try { doSomethingWith(s); } catch (Exception e) { LOGGER.warn("Had some kind of problem with string " + stringArray.indexOf(s) + ": " + s, e); } }


Si necesita un contador en un bucle para cada uno, debe contar usted mismo. No hay un contador integrado por lo que sé.


Uno de los cambios que Sun está considerando para Java7 es proporcionar acceso al Iterator interno en los bucles foreach. La sintaxis será algo como esto (si esto es aceptado):

for (String str : list : it) { if (str.length() > 100) { it.remove(); } }

Esto es azúcar sintáctica, pero aparentemente se hicieron muchas solicitudes para esta característica. Pero hasta que se apruebe, tendrá que contar las iteraciones usted mismo o usar un bucle regular con un Iterator .


int i = 0; for(String s : stringArray) { doSomethingWith(s,i); ++i; }

Hay muchas formas pero el método es una de las formas.