Java 8 Collectors.groupingBy with mapped value to set collecting result to the same set
up vote
10
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
10
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
10
down vote
favorite
up vote
10
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 Nov 27 at 8:14
ernest_k
18.1k41838
18.1k41838
asked Nov 27 at 8:06
Sergii
2,39951847
2,39951847
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
Nov 27 at 9:12
@nullpointer it should beat.getKey()
. thanks
– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
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
Nov 27 at 8:50
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
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
Nov 27 at 9:12
@nullpointer it should beat.getKey()
. thanks
– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
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
Nov 27 at 9:12
@nullpointer it should beat.getKey()
. thanks
– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
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 Nov 27 at 9:13
answered Nov 27 at 8:16
Eran
274k35439521
274k35439521
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
Nov 27 at 9:12
@nullpointer it should beat.getKey()
. thanks
– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
add a comment |
What'sat.getKey
, might be a typo there with a missing()
– nullpointer
Nov 27 at 9:12
@nullpointer it should beat.getKey()
. thanks
– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
What's
at.getKey
, might be a typo there with a missing ()
– nullpointer
Nov 27 at 9:12
What's
at.getKey
, might be a typo there with a missing ()
– nullpointer
Nov 27 at 9:12
@nullpointer it should be
at.getKey()
. thanks– Eran
Nov 27 at 9:13
@nullpointer it should be
at.getKey()
. thanks– Eran
Nov 27 at 9:13
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
Nov 27 at 10:39
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
Nov 27 at 10:39
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
Nov 27 at 8:50
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
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
Nov 27 at 8:50
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
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 Nov 27 at 11:32
answered Nov 27 at 8:23
Ravindra Ranwala
7,91831533
7,91831533
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
Nov 27 at 8:50
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
add a comment |
3
Nice! I'd only suggestorElseGet(HashMap::new)
instead oforElse(new HashMap<>())
to make it a little bit cleaner.
– Tomasz Linkowski
Nov 27 at 8:50
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.
– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to beorElseGet
instead oforElse
. I made the proper edit.
– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
3
3
Nice! I'd only suggest
orElseGet(HashMap::new)
instead of orElse(new HashMap<>())
to make it a little bit cleaner.– Tomasz Linkowski
Nov 27 at 8:50
Nice! I'd only suggest
orElseGet(HashMap::new)
instead of orElse(new HashMap<>())
to make it a little bit cleaner.– Tomasz Linkowski
Nov 27 at 8:50
2
2
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.– nullpointer
Nov 27 at 9:09
orElse(HashMap::new)
wouldn't compiler either...made an edit for the same.– nullpointer
Nov 27 at 9:09
@nullpointer It was supposed to be
orElseGet
instead of orElse
. I made the proper edit.– Tomasz Linkowski
Nov 27 at 9:24
@nullpointer It was supposed to be
orElseGet
instead of orElse
. I made the proper edit.– Tomasz Linkowski
Nov 27 at 9:24
@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
Nov 27 at 9:31
@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
Nov 27 at 9:31
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
@nullpointer It's just for readability. In terms of execution, the difference is most likely insignificant.
– Tomasz Linkowski
Nov 27 at 9:47
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 Nov 27 at 8:24
Tomasz Linkowski
2,775821
2,775821
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