Merge list of maps into a single map by summing values
.everyoneloves__top-leaderboard:empty,.everyoneloves__mid-leaderboard:empty,.everyoneloves__bot-mid-leaderboard:empty{ height:90px;width:728px;box-sizing:border-box;
}
I have a class Values:
public class Values {
private int count;
private int values;
}
And a list of multiple maps of type Map<String, Values>
Map<String, Values> map1 = new HashMap<>();
map1 .put("aaa", new Values(1, 10));
map1 .put("bbb", new Values(5, 50));
map1 .put("ccc", new Values(2, 30));
Map<String, Values> map2= new HashMap<>();
map2.put("aaa", new Values(2, 20));
map2.put("bbb", new Values(3, 50));
map2.put("ccc", new Values(3, 10));
List<Map<String, Values>> list = Arrays.asList(map1, map2);
There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.
I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:
{
aaa= {
count = 3,
value = 30
},
bbb= {
count = 8,
value = 100
},
ccc= {
count = 6,
value = 40
}
}
I am trying to achieve this using the Streams API, but I am stuck:
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream()) ...?
}
How can I group each entry by their keys and add up each count and each value into a single map?
Thank you in advance.
java java-8 java-stream
add a comment |
I have a class Values:
public class Values {
private int count;
private int values;
}
And a list of multiple maps of type Map<String, Values>
Map<String, Values> map1 = new HashMap<>();
map1 .put("aaa", new Values(1, 10));
map1 .put("bbb", new Values(5, 50));
map1 .put("ccc", new Values(2, 30));
Map<String, Values> map2= new HashMap<>();
map2.put("aaa", new Values(2, 20));
map2.put("bbb", new Values(3, 50));
map2.put("ccc", new Values(3, 10));
List<Map<String, Values>> list = Arrays.asList(map1, map2);
There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.
I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:
{
aaa= {
count = 3,
value = 30
},
bbb= {
count = 8,
value = 100
},
ccc= {
count = 6,
value = 40
}
}
I am trying to achieve this using the Streams API, but I am stuck:
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream()) ...?
}
How can I group each entry by their keys and add up each count and each value into a single map?
Thank you in advance.
java java-8 java-stream
add a comment |
I have a class Values:
public class Values {
private int count;
private int values;
}
And a list of multiple maps of type Map<String, Values>
Map<String, Values> map1 = new HashMap<>();
map1 .put("aaa", new Values(1, 10));
map1 .put("bbb", new Values(5, 50));
map1 .put("ccc", new Values(2, 30));
Map<String, Values> map2= new HashMap<>();
map2.put("aaa", new Values(2, 20));
map2.put("bbb", new Values(3, 50));
map2.put("ccc", new Values(3, 10));
List<Map<String, Values>> list = Arrays.asList(map1, map2);
There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.
I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:
{
aaa= {
count = 3,
value = 30
},
bbb= {
count = 8,
value = 100
},
ccc= {
count = 6,
value = 40
}
}
I am trying to achieve this using the Streams API, but I am stuck:
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream()) ...?
}
How can I group each entry by their keys and add up each count and each value into a single map?
Thank you in advance.
java java-8 java-stream
I have a class Values:
public class Values {
private int count;
private int values;
}
And a list of multiple maps of type Map<String, Values>
Map<String, Values> map1 = new HashMap<>();
map1 .put("aaa", new Values(1, 10));
map1 .put("bbb", new Values(5, 50));
map1 .put("ccc", new Values(2, 30));
Map<String, Values> map2= new HashMap<>();
map2.put("aaa", new Values(2, 20));
map2.put("bbb", new Values(3, 50));
map2.put("ccc", new Values(3, 10));
List<Map<String, Values>> list = Arrays.asList(map1, map2);
There could be any number of maps and any number of entries inside the maps, but the keys for the maps are always the same, only the values can differ. My example contains only 2 maps and only 3 entries for each map for clarity.
I want to obtain a single map with the same keys and with the Values objects as the sum of each "count" and each "value" in the objects, like this:
{
aaa= {
count = 3,
value = 30
},
bbb= {
count = 8,
value = 100
},
ccc= {
count = 6,
value = 40
}
}
I am trying to achieve this using the Streams API, but I am stuck:
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream()) ...?
}
How can I group each entry by their keys and add up each count and each value into a single map?
Thank you in advance.
java java-8 java-stream
java java-8 java-stream
edited Feb 10 at 10:31
Ruslan
4,57611230
4,57611230
asked Feb 10 at 9:32
stk020305stk020305
636
636
add a comment |
add a comment |
2 Answers
2
active
oldest
votes
You can collect the entries of your Stream
with a toMap
collector, with a merge function.
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1,v2) -> new Values(v1,v2)));
}
Assuming you have a Values
constructor that takes two Values
instances and creates an instance having the sums of the values.
Of course, you can write the merge function without that constructor. For example:
(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())
2
Regarding the constructor that twoValues
to represent(v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, callingValues::new
would rather be clean. Though using a static method to add these attributes and return back aValue
shall be a better choice in my opinion.
– Naman
Feb 10 at 12:05
add a comment |
One more solution with groupingBy:
Map<String, Optional<Values>> collect = list.stream()
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));
Note: values of this map are Optional<Values>
.
If you have null
value on one of your source map like map2.put("ddd", null);
it allows to avoid NullPointerException
and return Optional.empty
add a comment |
Your Answer
StackExchange.ifUsing("editor", function () {
StackExchange.using("externalEditor", function () {
StackExchange.using("snippets", function () {
StackExchange.snippets.init();
});
});
}, "code-snippets");
StackExchange.ready(function() {
var channelOptions = {
tags: "".split(" "),
id: "1"
};
initTagRenderer("".split(" "), "".split(" "), channelOptions);
StackExchange.using("externalEditor", function() {
// Have to fire editor after snippets, if snippets enabled
if (StackExchange.settings.snippets.snippetsEnabled) {
StackExchange.using("snippets", function() {
createEditor();
});
}
else {
createEditor();
}
});
function createEditor() {
StackExchange.prepareEditor({
heartbeatType: 'answer',
autoActivateHeartbeat: false,
convertImagesToLinks: true,
noModals: true,
showLowRepImageUploadWarning: true,
reputationToPostImages: 10,
bindNavPrevention: true,
postfix: "",
imageUploader: {
brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
allowUrls: true
},
onDemand: true,
discardSelector: ".discard-answer"
,immediatelyShowMarkdownHelp:true
});
}
});
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54615078%2fmerge-list-of-maps-into-a-single-map-by-summing-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
2 Answers
2
active
oldest
votes
2 Answers
2
active
oldest
votes
active
oldest
votes
active
oldest
votes
You can collect the entries of your Stream
with a toMap
collector, with a merge function.
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1,v2) -> new Values(v1,v2)));
}
Assuming you have a Values
constructor that takes two Values
instances and creates an instance having the sums of the values.
Of course, you can write the merge function without that constructor. For example:
(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())
2
Regarding the constructor that twoValues
to represent(v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, callingValues::new
would rather be clean. Though using a static method to add these attributes and return back aValue
shall be a better choice in my opinion.
– Naman
Feb 10 at 12:05
add a comment |
You can collect the entries of your Stream
with a toMap
collector, with a merge function.
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1,v2) -> new Values(v1,v2)));
}
Assuming you have a Values
constructor that takes two Values
instances and creates an instance having the sums of the values.
Of course, you can write the merge function without that constructor. For example:
(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())
2
Regarding the constructor that twoValues
to represent(v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, callingValues::new
would rather be clean. Though using a static method to add these attributes and return back aValue
shall be a better choice in my opinion.
– Naman
Feb 10 at 12:05
add a comment |
You can collect the entries of your Stream
with a toMap
collector, with a merge function.
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1,v2) -> new Values(v1,v2)));
}
Assuming you have a Values
constructor that takes two Values
instances and creates an instance having the sums of the values.
Of course, you can write the merge function without that constructor. For example:
(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())
You can collect the entries of your Stream
with a toMap
collector, with a merge function.
public static Map<String, Values> mergeMaps(List<Map<String, Values>> maps) {
return maps.stream()
.flatMap(m -> m.entrySet().stream())
.collect(Collectors.toMap(Map.Entry::getKey,
Map.Entry::getValue,
(v1,v2) -> new Values(v1,v2)));
}
Assuming you have a Values
constructor that takes two Values
instances and creates an instance having the sums of the values.
Of course, you can write the merge function without that constructor. For example:
(v1,v2) -> new Values(v1.getCount()+v2.getCount(),v1.getValue()+v2.getValue())
edited Feb 10 at 9:43
answered Feb 10 at 9:37
EranEran
292k37481564
292k37481564
2
Regarding the constructor that twoValues
to represent(v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, callingValues::new
would rather be clean. Though using a static method to add these attributes and return back aValue
shall be a better choice in my opinion.
– Naman
Feb 10 at 12:05
add a comment |
2
Regarding the constructor that twoValues
to represent(v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, callingValues::new
would rather be clean. Though using a static method to add these attributes and return back aValue
shall be a better choice in my opinion.
– Naman
Feb 10 at 12:05
2
2
Regarding the constructor that two
Values
to represent (v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new
would rather be clean. Though using a static method to add these attributes and return back a Value
shall be a better choice in my opinion.– Naman
Feb 10 at 12:05
Regarding the constructor that two
Values
to represent (v1,v2) -> new Values(v1,v2)
, I doubt how good a choice of having such a constructor be. Given if that really exists, calling Values::new
would rather be clean. Though using a static method to add these attributes and return back a Value
shall be a better choice in my opinion.– Naman
Feb 10 at 12:05
add a comment |
One more solution with groupingBy:
Map<String, Optional<Values>> collect = list.stream()
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));
Note: values of this map are Optional<Values>
.
If you have null
value on one of your source map like map2.put("ddd", null);
it allows to avoid NullPointerException
and return Optional.empty
add a comment |
One more solution with groupingBy:
Map<String, Optional<Values>> collect = list.stream()
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));
Note: values of this map are Optional<Values>
.
If you have null
value on one of your source map like map2.put("ddd", null);
it allows to avoid NullPointerException
and return Optional.empty
add a comment |
One more solution with groupingBy:
Map<String, Optional<Values>> collect = list.stream()
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));
Note: values of this map are Optional<Values>
.
If you have null
value on one of your source map like map2.put("ddd", null);
it allows to avoid NullPointerException
and return Optional.empty
One more solution with groupingBy:
Map<String, Optional<Values>> collect = list.stream()
.flatMap(map -> map.entrySet().stream())
.collect(groupingBy(Map.Entry::getKey, mapping(Map.Entry::getValue,
reducing((v1, v2) -> new Values(v1.count + v2.count, v1.values + v2.values)))));
Note: values of this map are Optional<Values>
.
If you have null
value on one of your source map like map2.put("ddd", null);
it allows to avoid NullPointerException
and return Optional.empty
answered Feb 10 at 10:11
RuslanRuslan
4,57611230
4,57611230
add a comment |
add a comment |
Thanks for contributing an answer to Stack Overflow!
- Please be sure to answer the question. Provide details and share your research!
But avoid …
- Asking for help, clarification, or responding to other answers.
- Making statements based on opinion; back them up with references or personal experience.
To learn more, see our tips on writing great answers.
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
StackExchange.ready(
function () {
StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f54615078%2fmerge-list-of-maps-into-a-single-map-by-summing-values%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Sign up or log in
StackExchange.ready(function () {
StackExchange.helpers.onClickDraftSave('#login-link');
});
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Sign up using Google
Sign up using Facebook
Sign up using Email and Password
Post as a guest
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown
Required, but never shown