代码之家  ›  专栏  ›  技术社区  ›  Kosi2801

是否有办法在Java中为每个循环访问一个迭代计数器?

  •  238
  • Kosi2801  · 技术社区  · 15 年前

    Java的每个循环都有一种方法吗?

    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循环中有这样一个计数器的唯一方法是什么?

    16 回复  |  直到 5 年前
        1
  •  172
  •   interestedparty333    8 年前

    不,但是你可以提供你自己的柜台。

    原因是for each循环内部没有 一个计数器;它基于 Iterable 接口,即它使用 Iterator 循环遍历“集合”—它可能根本不是集合,实际上可能根本不是基于索引的集合(如链接列表)。

        2
  •  58
  •   akuhn    15 年前

    还有另一种方法。

    既然你自己写了 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++); }
                        ...
                    }
                }
            }
        }
    }
    
        3
  •  40
  •   paxdiablo    8 年前

    最简单的解决方案 只需运行自己的计数器:

    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
    

    也就是说,顺序不被认为是集合的显著特征。

    还有其他方法可以做到 没有 一个手动计数器,但它是一个公平的工作,为可疑的利益。

        4
  •  23
  •   James Scriven    10 年前

    使用 兰姆达斯 功能接口 在里面 爪哇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);
          }
       }
    }
    

    图书馆将开始出现来做这些事情,或者你可以自己滚动。

        5
  •  16
  •   bruno conde    15 年前

    恐怕这是不可能的 foreach . 但是我可以建议你一个简单的 旧样式的循环 :

        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);
        }
    
        6
  •  15
  •   rmuller    8 年前

    Java 8介绍了 Iterable#forEach() / Map#forEach() 方法,对许多人来说更有效 Collection / Map 实现与每个循环的“经典”相比较。但是,在这种情况下,也没有提供索引。这里的诀窍是使用 AtomicInteger 在lambda表达式之外。注意:lambda表达式中使用的变量必须是有效的final,这就是为什么我们不能使用普通的 int .

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

    其中一个变化 Sun 正在考虑 Java7 提供进入内部的通道 Iterator 在foreach循环中。语法如下(如果接受此语法):

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

    这是句法上的甜头,但显然有很多人对这个特性提出了要求。但是,在获得批准之前,您必须自己计算迭代次数,或者使用带有 迭代器 .

        8
  •  5
  •   user177800    7 年前

    惯用解决方案:

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

    这实际上是谷歌在 Guava discussion 为什么他们没有提供 CountingIterator .

        9
  •  2
  •   John Topley    15 年前

    如果你需要在for-each循环中有一个计数器,你必须计算你自己。据我所知,没有内置计数器。

        10
  •  1
  •   Jörg    14 年前

    帕克斯的回答有一个“变种”…;-)

    int i = -1;
    for(String s : stringArray) {
        doSomethingWith(s, ++i);
    }
    
        11
  •  1
  •   Sankar Karthi    8 年前
    int i = 0;
    for(String s : stringArray) {
        doSomethingWith(s,i);
        ++i;
    } 
    

    有很多方法,但方法是其中之一

        12
  •  1
  •   Amar Prakash Pandey    6 年前

    尽管有很多其他的方法可以达到同样的效果,但是我会为一些不满意的用户分享我的方法。我正在使用Java 8的ItSt流特性。

    1。数组

    Object[] obj = {1,2,3,4,5,6,7};
    IntStream.range(0, obj.length).forEach(idx -> {
        System.out.println("index: " + index);
        System.out.println("value: " + obj[index]);
    });
    

    2。表

    List<String> strings = new ArrayList<String>();
    Collections.addAll(strings,"A","B","C","D");
    
    IntStream.range(0, strings.size()).forEach(idx -> {
        System.out.println("index: " + index);
        System.out.println("value: " + strings.get(idx));
    });
    
        13
  •  0
  •   HoldOffHunger Lux    7 年前

    我发现使用带有递增索引的简单for循环是最有效、最可靠的解决方案,如下所示: https://stackoverflow.com/a/3431543/2430549

        14
  •  0
  •   Jeremy    7 年前

    对于偶尔只需要索引的情况,例如在catch子句中,有时会使用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);
      }
    }
    
        15
  •  0
  •   ashkanaral    5 年前

    下面是一个我如何做到这一点的例子。这将在for each循环中获取索引。希望这有帮助。

    public class CheckForEachLoop {
    
        public static void main(String[] args) {
    
            int[] myIntArray = new int[11];
            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
                }
    
            }
            System.out.println(months[2]); 
    
    
        }
    }
    
        16
  •  -4
  •   Rik    13 年前

    我有点惊讶没有人提出以下建议(我承认这是一种懒惰的方法…); 如果StringArray是某种类型的列表,则可以使用StringArray.IndexOf之类的函数返回当前计数的值。

    注意:这假定列表中的元素是唯一的,或者它们是否是非唯一的并不重要(因为在这种情况下,它将返回找到的第一个副本的索引)。

    在某些情况下,这就足够了…