I have a map which consists of 3 lists as follows.
User user = new User();
user.setId(1);
// more user creation
List<User> usersOne Arrays.asList(user1, user2, user3);
// more lists created
// This is the map with 3 lists. Adding data to map
Map<String, List<User>> map = new HashMap<>();
map.put("key1", usersOne);
map.put("key2", usersTwo);
map.put("key3", usersThree);
Above is just to show example. This map is constructed this way and coming from a rest call.
Is there a way I could loop over those lists for all 3 keys and add per item to a new list?
Meaning like this.
List<User> data = new ArrayList<>();
List<User> list1 = map.get("key1");
List<User> list2 = map.get("key2");
List<User> list3 = map.get("key3");
data.add(list1.get(0));
data.add(list2.get(0));
data.add(list3.get(0));
// and then
data.add(list1.get(1));
data.add(list2.get(1));
data.add(list3.get(1));
and so on. Or a better way to do it. Ultimate looking to get a new list of the users by getting them in this manner, 1 from each list and then move on to next index.
Note that the 3 lists are not of same length.
Was looking to see if I could achieve it via something like the following.
But looks expensive. Could I get some advice on how I could achieve this pls? Thanks.
for (User list1User : list1) {
for (User list2User : list2) {
for (User list3User: list3) {
// write logic in here since I now do have access to all 3 lists.
// but is expensive plus also going to run into issues since the length is not the same for all 3 lists.
}
}
}
CodePudding user response:
Simple solution for your problem is "use index".
int size1 = list1.size();
int size2 = list2.size();
int size3 = list3.size();
//Choose maxSize of (size1,size2,size3)
int maxSize = Math.max(size1,size2);
maxSize = Math.max(maxSize,size3);
then use single loop, only add with condition i < listSize:
for(int i=0;i<maxSize;i ){
if(i < size1) data.add(list1.get(i);
if(i < size2) data.add(list2.get(i);
if(i < size3) data.add(list3.get(i);
}
In case you have more than 3 list in map:
Collection<List<Object>> allValues = map.values();
int maxSize = allValues.stream().map(list-> list.size()).max(Integer::compare).get();
List<Object> data = new ArrayList<>();
for(int i=0;i<maxSize;i ) {
for(List<Object> list: allValues) {
if(i < list.size()) data.add(list.get(i));
}
}
Ps: you might get warning because i am using notepad not editor tool.
CodePudding user response:
Not very simple but very concise and pragmatic would be to extract the lists from the map, flatten them and then collect them. Since Java 8 we can utilize streams for that.
List<User> data = map.values().stream()
.flatMap(users -> users.stream())
.collect(Collectors.toList());
With .values()
you get a Set<List<User>>
of your UserLists, i assume, that you don't need the keys.
With .flatMap()
we gather all users from each list. And we use flatMap()
instead of map()
because we want to retrieve the users from each list.
The last method-call .collect(Collectors.toList()
collects all elements from this stream and puts them into a read-only-list.
In this case, you would preserve multiple occurrences of the same user, which you wouldn't if you collect them as a set collect(Collectos.asSet())
, given they are really different objects.