user3458271
user3458271

Reputation: 660

Nested List to Map using streaming in java

I am getting some issues to convert my data to map, here are my data:

For e.g

[
  [abc, pqr, xyz], 
  [1, 2, 3], 
  [4, 5, 6],
  [1, 7, 8]
]

And i have to convert it into map as follow:

{
  1: [
    {abc:1, pqr:2,xyz:3},
    {abc:1, pqr:7,xyz:8}
  ],
  4: [
    {abc:4, pqr:5,xyz:6}
  ]
}

With basic for I know how to do it but with streaming, I am not getting it as I tried to do it with flatMap, reduce methods with a stream but maybe I am doing something very much wrong. So please can anyone help me out with this?

I tried something to flatMap and all as follow but stuck what to do:

List<List<Object>> dd = new ArrayList<List<Object>>();
final List<Object> dd1 = new ArrayList<Object>();
dd1.add("abc");
dd1.add("pqr");
dd1.add("xyz");
dd.add(dd1);

List<Object> dd2 = new ArrayList<Object>();
dd2.add("1");
dd2.add("2");
dd2.add("3");
dd.add(dd2);

dd2 = new ArrayList<Object>();
dd2.add("4");
dd2.add("5");
dd2.add("6");
dd.add(dd2);

Map<String, Object> m =  dd.stream().collect(Collectors.toMap(s -> (String) s.get(0), s -> s));
System.out.println(m);

Map<String, Object> m1 =  dd.stream().reduce((l1,l2) -> {
    return (new Map<String, Object>()).put(dd1.get(l2), l2);
}).orElse(new Map<String, Object>());

There are syntax errors I know in above code. Also, give some good links where can learn to stream nicely.

Upvotes: 0

Views: 430

Answers (2)

Ishank Gulati
Ishank Gulati

Reputation: 655

// get header and remove it from dataframe
List<String> header = dd.remove(0);

// key -> first element of row
// value -> extract from getValue method
// merge function -> merge both lists in case of conflict
Map<String, List<Map<String, String>>> tableAsMap = dd.stream().collect(Collectors.toMap(row -> row.get(0), row -> getValue(row, header), (list1, list2) -> {
    list1.addAll(list2);
    return list1;
}));

public List<Map<String, String>> getValue(List<String> row, List<String> header) {
    Map<String, String> map = new HashMap<>();
    IntStream.range(0, header.size())
            .forEach(idx -> map.put(header.get(idx), row.get(idx)));
    List<Map<String, String>> ret = new ArrayList<>();
    ret.add(map);
    return ret;
}

Upvotes: 1

Samuel Philipp
Samuel Philipp

Reputation: 11032

You can simplify your whole code to this:

List<String> header = dd.remove(0);
Map<Integer, List<Map<String, Integer>>> result = dd.stream()
        .map(row -> IntStream.range(0, Math.min(row.size(), header.size())).boxed()
                .collect(Collectors.toMap(header::get, i -> Integer.parseInt(row.get(i)))))
        .collect(Collectors.groupingBy(m -> m.get("abc")));

First use extract the header using List.remove(). After that you create a map for each row by replacing the list index with the header field as key (also parse the value as int). Finally you can use Collectors.groupingBy() with m -> m.get("abc") to group the result by the abc value.

Upvotes: 0

Related Questions