jhamm
jhamm

Reputation: 25022

Create map from Java stream?

I am trying to create a map from a Java stream. I am able to do this easily with javascript and am trying to create the same thing in Java. Here is my data structure:

var slips = [
  {
    original: 'Y',
    lines: [
      {
        detailLines: {
          detailLineId: 111
        }
      },
      {
        detailLines: {
          detailLineId: 222
        }
      }
    ]
  },
  {
    original: 'N',
    lines: [
      {
        detailLines: {
          detailLineId: 333
        }
      },
      {
        detailLines: {
          detailLineId: 444
        }
      }
    ]
  }
]

Here is how I did it in javascript

var test = slips.reduce((acc, slip) => {
  slip.lines.map(line => line.detailLines.detailLineId)
            .map(arr => acc[arr] = slip.original);
  return acc;
}, {});

to get my result of

{ 
  '111': 'Y', 
  '222': 'Y', 
  '333': 'N', 
  '444': 'N' 
}

How do I do this using the Java 8 Stream api? The slips above really is just a POJO. I converted it to a JSON object to do figure it out in js. The real structure of the Objects are

class Slip {
  private Boolean original;
  private List<Line> lines;
}

class Line {
  private List<DetailLine> detailLines;
}

class DetailLine {
  private Long detailLine;
}

So what I have started with the Java is

Map<Long, Boolean> results = slips.stream().reduce(new Map<Long, Boolean>, ...)

Upvotes: 1

Views: 7384

Answers (2)

JWS
JWS

Reputation: 168

Here is a working example

import java.util.*;
import java.util.stream.Collectors;

public class Main {

    public static void main(String[] args) {

        List<DetailLine> detailedLines1 = new ArrayList<DetailLine>();
        detailedLines1.add(new DetailLine(111l));
        detailedLines1.add(new DetailLine(222l));

        List<DetailLine> detailedLines2 = new ArrayList<DetailLine>();
        detailedLines2.add(new DetailLine(333l));
        detailedLines2.add(new DetailLine(444l));


        Line line1 = new Line(detailedLines1);
        Line line2 = new Line(detailedLines2);


        List<Line> lines1 = new ArrayList<Line>();
        lines1.add(line1);

        List<Line> lines2 = new ArrayList<Line>();
        lines2.add(line2);

        List<Slip> slips = new ArrayList<Slip>();
        slips.add(new Slip(true, lines1));
        slips.add(new Slip(false, lines2));

        Map<Long, Boolean> myResult = new HashMap<>();


        slips.stream().map(
                slip ->
                        slip.getLines().stream().map(
                                line -> line.getDetailLines().stream().map(deadLine -> deadLine.getDetailLine()).collect(Collectors.toList())
                        ).flatMap(Collection::stream)
                                .map(l -> new AbstractMap.SimpleEntry<>(l, slip.getOriginal()))
        ).flatMap(l -> l).forEach(System.out::println);
    }

}

Output

111=true
222=true
333=false
444=false

Upvotes: 0

Alexis C.
Alexis C.

Reputation: 93842

For me, it looks like a line object contains a single detail line and not a list.

class Slip {
    private Boolean original;
    private List<Line> lines;
}

class Line {
    private DetailLine detailLine;
}

class DetailLine {
    private Long detailLineId;
}

Assuming each detail line id is unique, you might use flatMap to create the necessary mappings id -> Boolean, and simply collects them into a map.

import java.util.AbstractMap.SimpleEntry;
import static java.util.stream.Collectors.toMap;

...

Map<Long, Boolean> results =  
    slips.stream()
         .flatMap(s -> s.getLines().stream().map(l -> new SimpleEntry<>(l.getDetailLine().getDetailLineId(), s.getOriginal())))
         .collect(toMap(SimpleEntry::getKey, SimpleEntry::getValue))

If you indeed have the structure you claimed, you should flatMap twice:

.flatMap(s -> s.getLines().stream().flatMap(l -> l.getDetailLine().stream().map(dl -> new SimpleEntry<>(dl.getDetailLineId(), s.getOriginal()))))

Upvotes: 2

Related Questions