Java 8 Collectors.groupingBy with mapped value to set collecting result to the same set
up vote
9
down vote
favorite
Objects are used in example are from package org.jsoup.nodes
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
I need group attributes by key with resulting value Set
.
Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button -> button.attributes().asList().stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute -> attribute.getValue(), toSet()))))
.orElse(new HashMap<>());
It seems collected correctly, but value all the time is single string (because of library implementation) that contains different values split by space. Trying to improve solution:
Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
button -> button.attributes()
.asList()
.stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute ->
new HashSet<String>(Arrays.asList(attribute.getValue()
.split(" "))),
toSet()))))
.orElse(new HashMap<>());
In result i've got different structure Map<String, Set<HashSet<String>>>
but i need Map<String, Set<String>>
I've checked some collectors but have not managed my issue.
Question is:
How to merge all sets that related to the same attribute key?
java lambda java-8 java-stream collectors
add a comment |
up vote
9
down vote
favorite
Objects are used in example are from package org.jsoup.nodes
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
I need group attributes by key with resulting value Set
.
Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button -> button.attributes().asList().stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute -> attribute.getValue(), toSet()))))
.orElse(new HashMap<>());
It seems collected correctly, but value all the time is single string (because of library implementation) that contains different values split by space. Trying to improve solution:
Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
button -> button.attributes()
.asList()
.stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute ->
new HashSet<String>(Arrays.asList(attribute.getValue()
.split(" "))),
toSet()))))
.orElse(new HashMap<>());
In result i've got different structure Map<String, Set<HashSet<String>>>
but i need Map<String, Set<String>>
I've checked some collectors but have not managed my issue.
Question is:
How to merge all sets that related to the same attribute key?
java lambda java-8 java-stream collectors
add a comment |
up vote
9
down vote
favorite
up vote
9
down vote
favorite
Objects are used in example are from package org.jsoup.nodes
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
I need group attributes by key with resulting value Set
.
Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button -> button.attributes().asList().stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute -> attribute.getValue(), toSet()))))
.orElse(new HashMap<>());
It seems collected correctly, but value all the time is single string (because of library implementation) that contains different values split by space. Trying to improve solution:
Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
button -> button.attributes()
.asList()
.stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute ->
new HashSet<String>(Arrays.asList(attribute.getValue()
.split(" "))),
toSet()))))
.orElse(new HashMap<>());
In result i've got different structure Map<String, Set<HashSet<String>>>
but i need Map<String, Set<String>>
I've checked some collectors but have not managed my issue.
Question is:
How to merge all sets that related to the same attribute key?
java lambda java-8 java-stream collectors
Objects are used in example are from package org.jsoup.nodes
import org.jsoup.nodes.Attribute;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
I need group attributes by key with resulting value Set
.
Optional<Element> buttonOpt = ...;
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button -> button.attributes().asList().stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute -> attribute.getValue(), toSet()))))
.orElse(new HashMap<>());
It seems collected correctly, but value all the time is single string (because of library implementation) that contains different values split by space. Trying to improve solution:
Map<String, Set<HashSet<String>>> stringSetMap = buttonOpt.map(
button -> button.attributes()
.asList()
.stream()
.collect(groupingBy(Attribute::getKey,
mapping(attribute ->
new HashSet<String>(Arrays.asList(attribute.getValue()
.split(" "))),
toSet()))))
.orElse(new HashMap<>());
In result i've got different structure Map<String, Set<HashSet<String>>>
but i need Map<String, Set<String>>
I've checked some collectors but have not managed my issue.
Question is:
How to merge all sets that related to the same attribute key?
java lambda java-8 java-stream collectors
java lambda java-8 java-stream collectors
edited 2 days ago
ernest_k
18.1k41838
18.1k41838
asked 2 days ago
Sergii
2,39451846
2,39451846
add a comment |
add a comment |
3 Answers
3
active
oldest
votes
up vote
9
down vote
accepted
You can split your attributes with flatMap
and create new entries to group:
Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button ->
button.attributes()
.asList()
.stream()
.flatMap(at -> Arrays.stream(at.getValue().split(" "))
.map(v -> new SimpleEntry<>(at.getKey(),v)))
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue, toSet()))))
.orElse(new HashMap<>());
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
2 days ago
@nullpointer it should beat.getKey()
. thanks
– Eran
2 days ago
2
I suggest usingorElse(Collections.emptyMap())
instead, as there is no need to instantiate a newHashMap
(and thegroupingBy
collector without a map supplier doesn’t guaranty to produce aHashMap
, so the caller should not assume it).
– Holger
2 days ago
add a comment |
up vote
11
down vote
Here's a Java9 way of doing it,
Map<String, Set<String>> stringSetMap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
.orElse(Collections.emptyMap());
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
2 days ago
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
2 days ago
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't thinkorElse
andorElseGet
would make difference. But still, both of them should execute just fine.
– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
add a comment |
up vote
5
down vote
This becomes less complicated if you use a more suitable data structure for it, namely a multimap.
Multimaps are present e.g. in Guava, where you can do this as follows:
SetMultimap<String, String> stringMultimap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Attribute::getKey,
attribute -> Arrays.stream(attribute.getValue().split(" "))
))
).orElse(ImmutableSetMultimap.of());
I made it immutable (ImmutableSetMultimap
), but a mutable version can also be obtained using Multimaps.flatteningToMultimap
.
add a comment |
3 Answers
3
active
oldest
votes
3 Answers
3
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
9
down vote
accepted
You can split your attributes with flatMap
and create new entries to group:
Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button ->
button.attributes()
.asList()
.stream()
.flatMap(at -> Arrays.stream(at.getValue().split(" "))
.map(v -> new SimpleEntry<>(at.getKey(),v)))
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue, toSet()))))
.orElse(new HashMap<>());
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
2 days ago
@nullpointer it should beat.getKey()
. thanks
– Eran
2 days ago
2
I suggest usingorElse(Collections.emptyMap())
instead, as there is no need to instantiate a newHashMap
(and thegroupingBy
collector without a map supplier doesn’t guaranty to produce aHashMap
, so the caller should not assume it).
– Holger
2 days ago
add a comment |
up vote
9
down vote
accepted
You can split your attributes with flatMap
and create new entries to group:
Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button ->
button.attributes()
.asList()
.stream()
.flatMap(at -> Arrays.stream(at.getValue().split(" "))
.map(v -> new SimpleEntry<>(at.getKey(),v)))
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue, toSet()))))
.orElse(new HashMap<>());
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
2 days ago
@nullpointer it should beat.getKey()
. thanks
– Eran
2 days ago
2
I suggest usingorElse(Collections.emptyMap())
instead, as there is no need to instantiate a newHashMap
(and thegroupingBy
collector without a map supplier doesn’t guaranty to produce aHashMap
, so the caller should not assume it).
– Holger
2 days ago
add a comment |
up vote
9
down vote
accepted
up vote
9
down vote
accepted
You can split your attributes with flatMap
and create new entries to group:
Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button ->
button.attributes()
.asList()
.stream()
.flatMap(at -> Arrays.stream(at.getValue().split(" "))
.map(v -> new SimpleEntry<>(at.getKey(),v)))
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue, toSet()))))
.orElse(new HashMap<>());
You can split your attributes with flatMap
and create new entries to group:
Optional<Element> buttonOpt = ...
Map<String, Set<String>> stringStringMap =
buttonOpt.map(button ->
button.attributes()
.asList()
.stream()
.flatMap(at -> Arrays.stream(at.getValue().split(" "))
.map(v -> new SimpleEntry<>(at.getKey(),v)))
.collect(groupingBy(Map.Entry::getKey,
mapping(Map.Entry::getValue, toSet()))))
.orElse(new HashMap<>());
edited 2 days ago
answered 2 days ago
Eran
274k35438521
274k35438521
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
2 days ago
@nullpointer it should beat.getKey()
. thanks
– Eran
2 days ago
2
I suggest usingorElse(Collections.emptyMap())
instead, as there is no need to instantiate a newHashMap
(and thegroupingBy
collector without a map supplier doesn’t guaranty to produce aHashMap
, so the caller should not assume it).
– Holger
2 days ago
add a comment |
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
2 days ago
@nullpointer it should beat.getKey()
. thanks
– Eran
2 days ago
2
I suggest usingorElse(Collections.emptyMap())
instead, as there is no need to instantiate a newHashMap
(and thegroupingBy
collector without a map supplier doesn’t guaranty to produce aHashMap
, so the caller should not assume it).
– Holger
2 days ago
What's
at.getKey
, might be a typo there with a missing ()
– nullpointer
2 days ago
What's
at.getKey
, might be a typo there with a missing ()
– nullpointer
2 days ago
@nullpointer it should be
at.getKey()
. thanks– Eran
2 days ago
@nullpointer it should be
at.getKey()
. thanks– Eran
2 days ago
2
2
I suggest using
orElse(Collections.emptyMap())
instead, as there is no need to instantiate a new HashMap
(and the groupingBy
collector without a map supplier doesn’t guaranty to produce a HashMap
, so the caller should not assume it).– Holger
2 days ago
I suggest using
orElse(Collections.emptyMap())
instead, as there is no need to instantiate a new HashMap
(and the groupingBy
collector without a map supplier doesn’t guaranty to produce a HashMap
, so the caller should not assume it).– Holger
2 days ago
add a comment |
up vote
11
down vote
Here's a Java9 way of doing it,
Map<String, Set<String>> stringSetMap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
.orElse(Collections.emptyMap());
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
2 days ago
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
2 days ago
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't thinkorElse
andorElseGet
would make difference. But still, both of them should execute just fine.
– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
add a comment |
up vote
11
down vote
Here's a Java9 way of doing it,
Map<String, Set<String>> stringSetMap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
.orElse(Collections.emptyMap());
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
2 days ago
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
2 days ago
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't thinkorElse
andorElseGet
would make difference. But still, both of them should execute just fine.
– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
add a comment |
up vote
11
down vote
up vote
11
down vote
Here's a Java9 way of doing it,
Map<String, Set<String>> stringSetMap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
.orElse(Collections.emptyMap());
Here's a Java9 way of doing it,
Map<String, Set<String>> stringSetMap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(Collectors.groupingBy(Attribute::getKey, Collectors.flatMapping(
attribute -> Arrays.stream(attribute.getValue().split(" ")), Collectors.toSet()))))
.orElse(Collections.emptyMap());
edited 2 days ago
answered 2 days ago
Ravindra Ranwala
7,94331533
7,94331533
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
2 days ago
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
2 days ago
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't thinkorElse
andorElseGet
would make difference. But still, both of them should execute just fine.
– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
add a comment |
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
2 days ago
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
2 days ago
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't thinkorElse
andorElseGet
would make difference. But still, both of them should execute just fine.
– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
3
3
Nice! I'd only suggest
orElseGet(HashMap::new)
instead of orElse(new HashMap<>())
to make it a little bit cleaner.– Tomasz Linkowski
2 days ago
Nice! I'd only suggest
orElseGet(HashMap::new)
instead of orElse(new HashMap<>())
to make it a little bit cleaner.– Tomasz Linkowski
2 days ago
2
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.– nullpointer
2 days ago
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.– nullpointer
2 days ago
@nullpointer It was supposed to be
orElseGet
instead of orElse
. I made the proper edit.– Tomasz Linkowski
2 days ago
@nullpointer It was supposed to be
orElseGet
instead of orElse
. I made the proper edit.– Tomasz Linkowski
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't think
orElse
and orElseGet
would make difference. But still, both of them should execute just fine.– nullpointer
2 days ago
@TomaszLinkowski Well for an initialization of a HashMap I don't think
orElse
and orElseGet
would make difference. But still, both of them should execute just fine.– nullpointer
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
2 days ago
add a comment |
up vote
5
down vote
This becomes less complicated if you use a more suitable data structure for it, namely a multimap.
Multimaps are present e.g. in Guava, where you can do this as follows:
SetMultimap<String, String> stringMultimap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Attribute::getKey,
attribute -> Arrays.stream(attribute.getValue().split(" "))
))
).orElse(ImmutableSetMultimap.of());
I made it immutable (ImmutableSetMultimap
), but a mutable version can also be obtained using Multimaps.flatteningToMultimap
.
add a comment |
up vote
5
down vote
This becomes less complicated if you use a more suitable data structure for it, namely a multimap.
Multimaps are present e.g. in Guava, where you can do this as follows:
SetMultimap<String, String> stringMultimap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Attribute::getKey,
attribute -> Arrays.stream(attribute.getValue().split(" "))
))
).orElse(ImmutableSetMultimap.of());
I made it immutable (ImmutableSetMultimap
), but a mutable version can also be obtained using Multimaps.flatteningToMultimap
.
add a comment |
up vote
5
down vote
up vote
5
down vote
This becomes less complicated if you use a more suitable data structure for it, namely a multimap.
Multimaps are present e.g. in Guava, where you can do this as follows:
SetMultimap<String, String> stringMultimap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Attribute::getKey,
attribute -> Arrays.stream(attribute.getValue().split(" "))
))
).orElse(ImmutableSetMultimap.of());
I made it immutable (ImmutableSetMultimap
), but a mutable version can also be obtained using Multimaps.flatteningToMultimap
.
This becomes less complicated if you use a more suitable data structure for it, namely a multimap.
Multimaps are present e.g. in Guava, where you can do this as follows:
SetMultimap<String, String> stringMultimap = buttonOpt
.map(button -> button.attributes().asList().stream()
.collect(ImmutableSetMultimap.flatteningToImmutableSetMultimap(
Attribute::getKey,
attribute -> Arrays.stream(attribute.getValue().split(" "))
))
).orElse(ImmutableSetMultimap.of());
I made it immutable (ImmutableSetMultimap
), but a mutable version can also be obtained using Multimaps.flatteningToMultimap
.
answered 2 days ago
Tomasz Linkowski
2,745821
2,745821
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.
Some of your past answers have not been well-received, and you're in danger of being blocked from answering.
Please pay close attention to the following guidance:
- 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%2f53495212%2fjava-8-collectors-groupingby-with-mapped-value-to-set-collecting-result-to-the-s%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