How to zip two Java Lists

Here's Java-8 solution using the Pair class (like in @ZhekaKozlov answer):

public static <A, B> List<Pair<A, B>> zipJava8(List<A> as, List<B> bs) {
    return IntStream.range(0, Math.min(as.size(), bs.size()))
            .mapToObj(i -> new Pair<>(as.get(i), bs.get(i)))
            .collect(Collectors.toList());
}

In Java 9 onwards you can use Map.entry():

    public static <A, B> List<Map.Entry<A, B>> zipJava8(List<A> as, List<B> bs) {
        return IntStream.range(0, Math.min(as.size(), bs.size()))
                .mapToObj(i -> Map.entry(as.get(i), bs.get(i)))
                .collect(Collectors.toList());
    }

As per related question, you can use Guava (>= 21.0) to do this:

List<String> subjectArr = Arrays.asList("aa", "bb", "cc");
List<Long> numArr = Arrays.asList(2L, 6L, 4L);
List<Pair> pairs = Streams.zip(subjectArr.stream(), numArr.stream(), Pair::new)
        .collect(Collectors.toList());

Note that the guava method is annotated as @Beta, though what that means in practice is up to interpretation, the method has not changed since version 21.0.


To get an Iterator<C> from an Iterator<A>, an Iterator<B>, and a BiFunction<A, B, C>:

public static <A, B, C> Iterator<C> map(Iterator<A> a, Iterator<B> b, BiFunction<A, B, C> f) {
    return new Iterator<C>() {
        public boolean hasNext() {
            return a.hasNext() && b.hasNext(); // This uses the shorter of the two `Iterator`s.
        }

        public C next() {
            return f.apply(a.next(), b.next());
        }
    };
}

Use an ArrayList of Map.Entry<String, Long>, checking that both arraylists have equal size (as it seems to be your requirement), like that:

List<Map.Entry<String,Long>> subjectNumArr = new ArrayList<>(numArr.size());
if (subjectArr.size() == numArr.size()) {
    for (int i = 0; i < subjectArr.size(); ++i) {
        subjectNumArr.add(new AbstractMap.SimpleEntry<String, Long>(subjectArr.get(i), numArr.get(i));
    }   
}

That's all the code you need!

Then, to iterate over the results, use something like:

for (Map.Entry<String, Long> entry : subjectNumArr) {
    String key = entry.getKey(); 
    Long value = entry.getValue();
}

or, you can simply get the pair at position i (keeping insertion order), by:

Map.Entry<String, Long> entry = subjectNumArr.get(i);

This can also hold duplicate entries, unlike the Map solution that I initially suggested, without requiring to define your own (Pair) class.


The operation you want is called zipping.

You need to implement a method zip:

public static <A, B> List<Pair<A, B>> zip(List<A> as, List<B> bs) {
  Iterator<A> it1 = as.iterator();
  Iterator<B> it2 = bs.iterator();
  List<Map.Entry<A, B>> result = new ArrayList<>();
  while (it1.hasNext() && it2.hasNext()) {
    result.add(Map.entry(it1.next(), it2.next()));
  }
  return result;
}

And you use it like this:

zip(subjectArr, numArr);