David Koelle
David Koelle

Reputation: 20834

How can I iterate through two arrays at one time using Java 8 streams?

I'm writing a Java program that gets data from a CSV file. For each row of data, I need to put each data element into a map using the corresponding header as a key. For example, headerRow[7] and dataElements[7] should be a key-value pair in the map.

Below is the code as I would write it traditionally using Java:

private Map<String, Double> readLine(String[] headerRow, String[] dataElements) {
    Map<String, Double> headerToDataMap = new HashMap<>(); 
    for (int i=0; i < nextLine.length; i++) {
        headerToDataMap.put(headerRow[i], Double.valueOf(dataElements[i]));
    }
    return headerToDataMap;
}

Is there a way that I can write this code using Java 8 streams, keeping in mind that I'm iterating on two arrays at the same time?

Upvotes: 5

Views: 5416

Answers (3)

M. Justin
M. Justin

Reputation: 21409

One solution would be to use a library that provides a method for zipping two streams together. Both the Guava and StreamEx libraries have such methods.

Guava

private Map<String, Double> readLine(String[] headerRow, String[] dataElements) {
    return Streams.zip(
                    Arrays.stream(headerRow),
                    Arrays.stream(dataElements),
                    (a, b) -> Map.entry(a, Double.valueOf(b)))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

StreamEx

private Map<String, Double> readLine(String[] headerRow, String[] dataElements) {
    return EntryStream.zip(headerRow, dataElements)
            .mapValues(Double::valueOf)
            .toMap();
}

or:

private Map<String, Double> readLine(String[] headerRow, String[] dataElements) {
    return StreamEx.zip(
                    headerRow,
                    dataElements,
                    (a, b) -> Map.entry(a, Double.valueOf(b)))
            .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
}

Upvotes: 0

alainlompo
alainlompo

Reputation: 4434

You can make something just a little longer using the BiFunction interface.

private Map<String, Double> readLine(String[] headerRow, String[] dataElements) {
        Map<String, Double> headerToDataMap = new HashMap<>();  
        BiFunction<String,String, KeyValue> toKeyValuePair = (s1,s2) -> new KeyValue(s1,s2);
        IntStream.range(0, nextLine.length)
                .mapToObj(i -> toKeyValuePair.apply(headerRow[i], dataElements[i]) )
                .collect(Collectors.toList())
                .stream()
                .forEach(kv -> {
                    headerToDataMap.put(kv.getKey(), Double.valueOf(kv.getValue()));
                });
        return headerToDataMap;
    }

The KeyValue type is a simple key value instance generator (code below)

private class KeyValue {
        String key;
        String value;
        public String getKey() {
            return key;
        }
        public void setKey(String key) {
            this.key = key;
        }
        public String getValue() {
            return value;
        }
        public void setValue(String value) {
            this.value = value;
        }
        public KeyValue(String key, String value) {
            super();
            this.key = key;
            this.value = value;
        }
        public KeyValue() {
            super();
        }       
    }

Upvotes: 1

Louis Wasserman
Louis Wasserman

Reputation: 198571

The closest thing you can get to this in vanilla Java 8 would probably be

 IntStream.range(0, nextLine.length())
    .boxed()
    .collect(toMap(i -> headerRow[i], i -> dataElements[i]));

Upvotes: 10

Related Questions