314

Javaのfor-eachループに方法はありますか

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

ループがすでに処理された頻度を調べるには?

古くてよく知られているfor(int i=0; i < boundary; i++)- ループを使用する以外に、構造は次のとおりです。

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

for-each ループでそのようなカウンターを使用できるようにする唯一の方法は?

4

16 に答える 16

234

いいえ。ただし、独自のカウンターを提供できます。

これは、for-each ループが内部的にカウンターを持たないためです。これはIterableインターフェースに基づいています。つまり、 を使用Iteratorして「コレクション」をループ処理します。コレクションはまったくコレクションではない可能性があり、実際にはインデックスにまったく基づいていないもの (リンクされたリストなど) である可能性があります。

于 2009-01-25T11:36:35.700 に答える
73

別の方法があります。

独自のクラスと、このクラスのオーバーインスタンスIndexを返す静的メソッドを作成すると、次のことができます。Iterable

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

の実装With.indexは次のようなものです

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++); }
                    ...
                }
            }
        }
    }
}
于 2009-09-29T08:45:30.327 に答える
61

最も簡単な解決策、次のように独自のカウンターを実行することです。

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

この理由は、コレクション内のアイテム (そのバリアントのfor反復処理)インデックスを持っているか、定義された順序を持っているという実際の保証がないためです(一部のコレクションでは、要素を追加または削除すると順序が変更される場合があります)。

たとえば、次のコードを参照してください。

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");
  }
}

それを実行すると、次のように表示されます。

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

当然のことながら、順序はセットの顕著な特徴とは見なされないことを示しています。

手動カウンターなしでそれを行う方法は他にもありますが、疑わしい利益のためにはかなりの作業です.

于 2009-01-25T11:18:48.967 に答える
28

Java 8ラムダ関数型インターフェイスを使用すると、新しいループの抽象化を作成できます。インデックスとコレクション サイズを使用して、コレクションをループできます。

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

どの出力:

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

私は次のように実装しました:

   @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());
      }
   }

可能性は無限大。たとえば、最初の要素だけに特別な関数を使用する抽象化を作成します。

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

コンマ区切りのリストを正しく出力するもの:

one,two,three,four

私は次のように実装しました:

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);
      }
   }
}

ライブラリは、これらの種類のことを行うためにポップアップし始めます。または、独自のライブラリを展開することもできます。

于 2014-04-05T13:22:47.380 に答える
17

残念ながら、これは では不可能foreachです。しかし、単純な古いスタイルの for ループを提案できます。

    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();
    }

Listインターフェイスから にアクセスできることに注意してくださいit.nextIndex()

(編集)

変更された例に:

    for(ListIterator<String> it =l.listIterator(); it.hasNext() ;)
    {
        int i = it.nextIndex();
        doSomethingWith(it.next(), i);
    }
于 2009-01-25T11:54:13.870 に答える
11

Sunfor を検討している変更の 1 つは、foreach ループJava7内の内部へのアクセスを提供することです。Iterator構文は次のようになります (これが受け入れられた場合):

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

これはシンタックス シュガーですが、この機能について多くのリクエストがあったようです。ただし、承認されるまでは、反復を自分でカウントするか、通常の for ループでIterator.

于 2009-01-25T12:43:29.153 に答える
2

for-each ループでカウンターが必要な場合は、自分自身をカウントする必要があります。私の知る限り、組み込みのカウンターはありません。

于 2009-01-25T11:13:12.377 に答える
1

pax の答えには「バリエーション」があります... ;-)

int i = -1;
for(String s : stringArray) {
    doSomethingWith(s, ++i);
}
于 2010-06-30T13:13:29.833 に答える
-4

私は誰も次のことを提案しなかったことに少し驚いています(私はそれが怠惰なアプローチであることを認めます...); stringArrayがある種のリストである場合、stringArray.indexOf(S)のようなものを使用して、現在のカウントの値を返すことができます。

注:これは、リストの要素が一意であること、またはそれらが一意でないかどうかは問題ではないことを前提としています(その場合、最初に見つかったコピーのインデックスが返されるため)。

それで十分な状況があります...

于 2011-03-04T23:02:27.683 に答える
-5

Here is an example of how I did this. This gets the index at the for each loop. Hope this helps.

public class CheckForEachLoop {

    public static void main(String[] args) {

        String[] months = new String[] { "JANUARY", "FEBRUARY", "MARCH", "APRIL", "MAY", "JUNE", "JULY", "AUGUST",
                "SEPTEMBER", "OCTOBER", "NOVEMBER", "DECEMBER" };
        for (String s : months) {
            if (s == months[2]) { // location where you can change
              doSomethingWith(s); // however many times s and months
                                  // doSomethingWith(s) will be completed and 
                                  // added together instead of counter
            }

        }
        System.out.println(s); 


    }
}
于 2019-02-18T23:06:38.890 に答える