Java - Iterating over every two elements in a list

前端 未结 11 2090
梦毁少年i
梦毁少年i 2020-12-19 04:26

What\'s the best way to iterate over a list while processing 2 elements at the same time?

Example:

List strings = Arrays.asList(\"item          


        
相关标签:
11条回答
  • 2020-12-19 05:24

    Now in Java 8, by using https://github.com/wapatesh/fig

    You can write:

    seq.forEachSlice(2, (values)->{
        // [1,2]  [3, 4]
    });
    
    0 讨论(0)
  • You can avoid indexing with an Iterator; this works for any Iterable, not just a list. Just get an iterator and increment it twice per loop iteration:

    List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
    Iterator<String> stringsIterator = strings.iterator();
    while (stringsIterator.hasNext()) {
      String first = stringsIterator.next();
      String second = stringsIterator.next();
      System.out.println("First [" + first + "] - Second [" + second + "]");
    }
    

    This assumes a list of even length, and throws NoSuchElementException on the last pass if it's odd length. You can handle this in various ways:

    • use a try-catch;
    • have a guard clause that checks that the length is even beforehand;
    • check before getting the second element.

    Checking the second element:

    List<String> strings = Arrays.asList("item 1", "item 2", "item 3");
    Iterator<String> stringsIterator = strings.iterator();
    while (stringsIterator.hasNext()) {
      String first = stringsIterator.next();
      String second = stringIterator.hasNext() ? stringIterator.next() : null;
      System.out.println("First [" + first + "] - Second [" + second + "]");
    }
    

    Iterators confuse some people, so you can also use a for-each loop with a branch and an auxiliary flip-flop variable for parity. This is much worse, since it makes the loop's logic much more complicated to simplify the iteration: rather than the action being done once per pass through the loop, in sequence and without branching, you instead have to go through it twice and branch mentally. Note that this skips the last element if it's of odd length; could add a check of isFirst afterwards if want to handle these cases too.

    List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
    boolean isFirst = true;
    String first = null;
    String second = null;
    for (String string : strings) {
      if (isFirst) {
        first = string;
        isFirst = false;
      } else {
        second = string;
        isFirst = true;
        System.out.println("First [" + first + "] - Second [" + second + "]");
      }
    }
    

    Lastly, note that all these iterators and auxiliary variables have excess scope (they are only of use for the loop itself, so they pollute the local environment): they could be wrapped in blocks to limit the scope, though usually the resulting nesting is considered worse than the excess scope:

    List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");
    {
      Iterator<String> stringsIterator = strings.iterator();
      while (stringsIterator.hasNext()) {
        String first = stringsIterator.next();
        String second = stringsIterator.next();
        System.out.println("First [" + first + "] - Second [" + second + "]");
      }
    }
    
    0 讨论(0)
  • 2020-12-19 05:29

    We should of course provide a solution for the general case ;-)

    public static void main(String[] args) {
        List<Integer> list = Arrays.asList(new Integer[] { 1, 2, 3, 4, 5, 6, 7, 8, 9 });
        for (Pair<Integer> p : Pair.over(list)) {
            System.out.printf("%d, %d\n", p.first, p.second);
        }
    }
    
    static class Pair<T> {
        T first;
    
        T second;
    
        public Pair(T first, T second) {
            this.first = first;
            this.second = second;
        }
    
        public static <T> Iterable<Pair<T>> over(Collection<T> collection) {
            return new PairWise<T>(collection);
        }
    
        private static class PairWise<T> implements Iterable<Pair<T>>, Iterator<Pair<T>> {
    
            final Iterator<T> iterator;
    
            PairWise(Collection<T> collection) {
                super();
                this.iterator = collection.iterator();
            }
    
            @Override
            public Iterator<Pair<T>> iterator() {
                return this;
            }
    
            @Override
            public boolean hasNext() {
                return iterator.hasNext();
            }
    
            @Override
            public Pair<T> next() {
                T first = null;
                T second = null;
                if (iterator.hasNext())
                    first = iterator.next();
                else
                    throw new NoSuchElementException();
                if (iterator.hasNext())
                    second = iterator.next();
                return new Pair<T>(first, second);
            }
    
            @Override
            public void remove() {
                throw new UnsupportedOperationException();
            }
    
        }
    }
    
    0 讨论(0)
  • 2020-12-19 05:30

    What if you increase i by 2 in each iteration? Should do... Otherwise consider increase i inside the actual loop

    0 讨论(0)
  • 2020-12-19 05:32
    List<String> strings = Arrays.asList("item 1", "item 2", "item 3", "item 4");    
    int i = 0;  
    for(; i < strings.size() - 1; i+=2){  
        String first = strings.get(i);  
        String second =  strings.get(i + 1);  
        System.out.println("First [" + first + "] - Second [" + second + "]");  
    }  
    //For odd sized lists
    if(i < strings.size()){         
        System.out.println("First [" + strings.get(i) + "]");  
    }
    
    0 讨论(0)
提交回复
热议问题