Orange Receptacle
Orange Receptacle

Reputation: 1183

Java: Transforming List<List> into a Map

Given a list of unique-valued sublists (that is to say two different sublists cannot share elements of the same value) - eg:

List[List[1, 1, 1], List[2], List[4, 4], List[7]]

how would this be transformed into a Map with a (value, size) key-value pairing?

This would result in:

{
  1 : 3
  2 : 1
  4 : 2
  7 : 1
}

Defining our List as values, I would assume that one could use streams and collect as a Map as such:

values.stream().collect(Collectors.toMap(Integer::intValue, ? ));

Currently unsure what to put in for the second parameter as it requires a value mapper but does not allow for .size() to be called upon any of the sublists.

Upvotes: 0

Views: 95

Answers (3)

MC Emperor
MC Emperor

Reputation: 22977

I think @rgettman's answer is the most elegant. However, it makes the presumption that all lists are non-empty. Of course this is easily fixed by simply adding .filter(list -> !list.isEmpty()) before the collect reduction operation.

This is another approach, which no longer considers the list to be 'two-dimensional', that is, List<List<Integer>>, but instead flattens it to just a stream of Integers.

Map<Integer, Long> map = lists.stream()
    .flatMap(Collection::stream)
    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));

Upvotes: 1

Dr Phil
Dr Phil

Reputation: 880

You could flatten the list and then use something like Collectors.groupingBy(Function.identity(), Collectors.counting()). However in this case i would say a good old (nested) for loop might be simpler to write and read.

List<List<Integer>> lst = Arrays.asList(Arrays.asList(1,1,1),Arrays.asList(2),Arrays.asList(4,4),Arrays.asList(7));

Map<Integer,Integer> result= new HashMap<Integer,Integer>();
System.out.println(lst);
//[[1, 1, 1], [2], [4, 4], [7]]

for(List<Integer> sub:lst){
  for(int n:sub){
    Integer last=result.get(n);
    int newCount=(last==null?0:last)+1;
    result.put(n, newCount);
  }
}
System.out.println(result);
//{1=3, 2=1, 4=2, 7=1}

Upvotes: 1

rgettman
rgettman

Reputation: 178263

When using Collectors.toMap, you need to specify how to get the key and the value from each element of the stream. Integer::intValue won't work here, because your stream elements are lists, not integers.

For the key, get the first element of the list. (This assumes that the inner lists are all non-empty.) For the value, pass the size method reference.

values.stream()
    .collect(Collectors.toMap(list -> list.get(0), List::size));

Upvotes: 7

Related Questions