Find only repeated String attributes in list with Java 8
I know below is the code to find out the occurrence of each String attributes in list , how can I filter this list with only duplicates item i.e having more than 1 occurrence. Sorry I am new to java 8 .
Map<String, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
java java-8 java-stream
add a comment |
I know below is the code to find out the occurrence of each String attributes in list , how can I filter this list with only duplicates item i.e having more than 1 occurrence. Sorry I am new to java 8 .
Map<String, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
java java-8 java-stream
add a comment |
I know below is the code to find out the occurrence of each String attributes in list , how can I filter this list with only duplicates item i.e having more than 1 occurrence. Sorry I am new to java 8 .
Map<String, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
java java-8 java-stream
I know below is the code to find out the occurrence of each String attributes in list , how can I filter this list with only duplicates item i.e having more than 1 occurrence. Sorry I am new to java 8 .
Map<String, Long> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()));
java java-8 java-stream
java java-8 java-stream
edited Dec 2 '18 at 19:57
Aomine
41.9k74071
41.9k74071
asked Dec 2 '18 at 19:51
Rishabh ChaturvediRishabh Chaturvedi
626
626
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
create a stream from the entrySet
and filter
:
List<Map.Entry<String, Long>> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(Collectors.toList());
or if you want to maintain a map then:
Map<String, Long> result = stringList().stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
on another note, if you just want the individual numbers that have more than or equal to 2 occurrences then you can do:
List<String> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.entrySet()
.stream()
.filter(x -> x.getValue() >= 2)
.map(Map.Entry::getKey)
.collect(toList());
another option being:
List<String> result =
list.stream()
.filter(x -> list.stream().filter(x::equals).limit(2).count() == 2)
.distinct()
.collect(toList());
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 '18 at 21:00
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution usinglastIndexOf
andindexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As forCollections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.
– Aomine
Dec 2 '18 at 21:19
|
show 1 more comment
If your List
is mutable, you can directly remove all elements except their second occurrence:
// example list
List<String> example = new ArrayList<>();
Collections.addAll(example, "foo", "bar", "baz", "bar", "bar", "baz");
// actual operation
Map<String,Integer> temp = new HashMap<>();
example.removeIf(s -> temp.merge(s, 1, Integer::sum)!=2);
// example output
example.forEach(System.out::println);// prints bar baz
The solution above keeps only one copy for each string having multiple occurrences while removing all strings having no duplicates. If you want to keep all duplicates and just remove those string not having duplicates, there is no way around determining the duplicate status first.
// same example input as above
// actual operation
Map<String,Boolean> temp = new HashMap<>();
example.forEach(s -> temp.merge(s, true, (a,b) -> false));
example.removeIf(temp::get);
// example output
example.forEach(System.out::println);// prints bar baz bar bar baz
Here, the temporary map can be created with a Stream operation with the same logic:
Map<String,Boolean> temp = example.stream()
.collect(Collectors.toMap(Function.identity(), s -> true, (a,b) -> false));
example.removeIf(temp::get);
add a comment |
The other way would be like this. after groupBy then remove entry with value=1;
result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.values().removeIf(v->v.intValue() == 1);
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.
– nullpointer
Dec 2 '18 at 21:16
4
@nullpointer there is no difference betweenresult.values().removeIf(v -> == 1)
andresult.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.
– Holger
Dec 2 '18 at 21:44
add a comment |
A simpler way to find that out could be
List<String> recurringItems = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toList());
Since for items occurring more than once, lastIndex wouldn't be equal to the first index.
Alternatively, you can use Collectors.toSet()
to ensure the items are listed only once in case you are not interested in their order of recurrence.
Set<String> recurringItemsOnce = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toSet());
Or using Collections.frequency
as:
Set<String> recurringItems = list.stream()
.filter(item -> Collections.frequency(list, item) >= 2)
.collect(Collectors.toSet());
this would retrieve duplicate items, e.g. if our list wasArrays.asList("1","2","3","1","56","4","4")
then as a result you'd have[1, 1, 4, 4]
instead of[1, 4]
which of course you could solve by adding adistinct
call after thefilter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.
– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the itemsdistinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.
– nullpointer
Dec 2 '18 at 20:28
3
Simpler in source code, but horrible regarding performance. The OP's original approach usinggroupingBy
as starting point is much preferable.
– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
indexOf
andlastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case offrequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.
– Holger
Dec 2 '18 at 21:40
|
show 2 more comments
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%2f53584012%2ffind-only-repeated-string-attributes-in-list-with-java-8%23new-answer', 'question_page');
}
);
Post as a guest
Required, but never shown
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
create a stream from the entrySet
and filter
:
List<Map.Entry<String, Long>> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(Collectors.toList());
or if you want to maintain a map then:
Map<String, Long> result = stringList().stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
on another note, if you just want the individual numbers that have more than or equal to 2 occurrences then you can do:
List<String> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.entrySet()
.stream()
.filter(x -> x.getValue() >= 2)
.map(Map.Entry::getKey)
.collect(toList());
another option being:
List<String> result =
list.stream()
.filter(x -> list.stream().filter(x::equals).limit(2).count() == 2)
.distinct()
.collect(toList());
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 '18 at 21:00
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution usinglastIndexOf
andindexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As forCollections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.
– Aomine
Dec 2 '18 at 21:19
|
show 1 more comment
create a stream from the entrySet
and filter
:
List<Map.Entry<String, Long>> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(Collectors.toList());
or if you want to maintain a map then:
Map<String, Long> result = stringList().stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
on another note, if you just want the individual numbers that have more than or equal to 2 occurrences then you can do:
List<String> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.entrySet()
.stream()
.filter(x -> x.getValue() >= 2)
.map(Map.Entry::getKey)
.collect(toList());
another option being:
List<String> result =
list.stream()
.filter(x -> list.stream().filter(x::equals).limit(2).count() == 2)
.distinct()
.collect(toList());
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 '18 at 21:00
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution usinglastIndexOf
andindexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As forCollections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.
– Aomine
Dec 2 '18 at 21:19
|
show 1 more comment
create a stream from the entrySet
and filter
:
List<Map.Entry<String, Long>> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(Collectors.toList());
or if you want to maintain a map then:
Map<String, Long> result = stringList().stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
on another note, if you just want the individual numbers that have more than or equal to 2 occurrences then you can do:
List<String> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.entrySet()
.stream()
.filter(x -> x.getValue() >= 2)
.map(Map.Entry::getKey)
.collect(toList());
another option being:
List<String> result =
list.stream()
.filter(x -> list.stream().filter(x::equals).limit(2).count() == 2)
.distinct()
.collect(toList());
create a stream from the entrySet
and filter
:
List<Map.Entry<String, Long>> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(Collectors.toList());
or if you want to maintain a map then:
Map<String, Long> result = stringList().stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()))
.entrySet()
.stream()
.filter(s -> s.getValue() >= 2)
.collect(toMap(Map.Entry::getKey, Map.Entry::getValue));
on another note, if you just want the individual numbers that have more than or equal to 2 occurrences then you can do:
List<String> result = list.stream()
.collect(Collectors.groupingBy(Function.identity(),
Collectors.counting()))
.entrySet()
.stream()
.filter(x -> x.getValue() >= 2)
.map(Map.Entry::getKey)
.collect(toList());
another option being:
List<String> result =
list.stream()
.filter(x -> list.stream().filter(x::equals).limit(2).count() == 2)
.distinct()
.collect(toList());
edited Dec 2 '18 at 20:37
answered Dec 2 '18 at 19:53
AomineAomine
41.9k74071
41.9k74071
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 '18 at 21:00
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution usinglastIndexOf
andindexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As forCollections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.
– Aomine
Dec 2 '18 at 21:19
|
show 1 more comment
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 '18 at 21:00
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution usinglastIndexOf
andindexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As forCollections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.
– Aomine
Dec 2 '18 at 21:19
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 '18 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 '18 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.– nullpointer
Dec 2 '18 at 21:00
list.stream() .filter(x -> list.stream().filter..
was pointing out this.– nullpointer
Dec 2 '18 at 21:00
1
1
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
Well, at least one such solution has been added to my answer. Just a choice to avoid using stream twice.
– nullpointer
Dec 2 '18 at 21:15
1
1
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution using
lastIndexOf
and indexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As for Collections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.– Aomine
Dec 2 '18 at 21:19
@nullpointer well creating a stream, in general, is a cheap operation. As for your solution using
lastIndexOf
and indexOf
, I am not quite sure how that would be compared to my last suggestion performance wise. As for Collections.frequency
I'd avoid that as it doesn't short circuit. imagine going through a list of thousands, millions of elements and all you're interested in is whether there is "2 or more occurrences of a particular object". the Stream solution above is efficient in the sense that it short-circuits.– Aomine
Dec 2 '18 at 21:19
|
show 1 more comment
If your List
is mutable, you can directly remove all elements except their second occurrence:
// example list
List<String> example = new ArrayList<>();
Collections.addAll(example, "foo", "bar", "baz", "bar", "bar", "baz");
// actual operation
Map<String,Integer> temp = new HashMap<>();
example.removeIf(s -> temp.merge(s, 1, Integer::sum)!=2);
// example output
example.forEach(System.out::println);// prints bar baz
The solution above keeps only one copy for each string having multiple occurrences while removing all strings having no duplicates. If you want to keep all duplicates and just remove those string not having duplicates, there is no way around determining the duplicate status first.
// same example input as above
// actual operation
Map<String,Boolean> temp = new HashMap<>();
example.forEach(s -> temp.merge(s, true, (a,b) -> false));
example.removeIf(temp::get);
// example output
example.forEach(System.out::println);// prints bar baz bar bar baz
Here, the temporary map can be created with a Stream operation with the same logic:
Map<String,Boolean> temp = example.stream()
.collect(Collectors.toMap(Function.identity(), s -> true, (a,b) -> false));
example.removeIf(temp::get);
add a comment |
If your List
is mutable, you can directly remove all elements except their second occurrence:
// example list
List<String> example = new ArrayList<>();
Collections.addAll(example, "foo", "bar", "baz", "bar", "bar", "baz");
// actual operation
Map<String,Integer> temp = new HashMap<>();
example.removeIf(s -> temp.merge(s, 1, Integer::sum)!=2);
// example output
example.forEach(System.out::println);// prints bar baz
The solution above keeps only one copy for each string having multiple occurrences while removing all strings having no duplicates. If you want to keep all duplicates and just remove those string not having duplicates, there is no way around determining the duplicate status first.
// same example input as above
// actual operation
Map<String,Boolean> temp = new HashMap<>();
example.forEach(s -> temp.merge(s, true, (a,b) -> false));
example.removeIf(temp::get);
// example output
example.forEach(System.out::println);// prints bar baz bar bar baz
Here, the temporary map can be created with a Stream operation with the same logic:
Map<String,Boolean> temp = example.stream()
.collect(Collectors.toMap(Function.identity(), s -> true, (a,b) -> false));
example.removeIf(temp::get);
add a comment |
If your List
is mutable, you can directly remove all elements except their second occurrence:
// example list
List<String> example = new ArrayList<>();
Collections.addAll(example, "foo", "bar", "baz", "bar", "bar", "baz");
// actual operation
Map<String,Integer> temp = new HashMap<>();
example.removeIf(s -> temp.merge(s, 1, Integer::sum)!=2);
// example output
example.forEach(System.out::println);// prints bar baz
The solution above keeps only one copy for each string having multiple occurrences while removing all strings having no duplicates. If you want to keep all duplicates and just remove those string not having duplicates, there is no way around determining the duplicate status first.
// same example input as above
// actual operation
Map<String,Boolean> temp = new HashMap<>();
example.forEach(s -> temp.merge(s, true, (a,b) -> false));
example.removeIf(temp::get);
// example output
example.forEach(System.out::println);// prints bar baz bar bar baz
Here, the temporary map can be created with a Stream operation with the same logic:
Map<String,Boolean> temp = example.stream()
.collect(Collectors.toMap(Function.identity(), s -> true, (a,b) -> false));
example.removeIf(temp::get);
If your List
is mutable, you can directly remove all elements except their second occurrence:
// example list
List<String> example = new ArrayList<>();
Collections.addAll(example, "foo", "bar", "baz", "bar", "bar", "baz");
// actual operation
Map<String,Integer> temp = new HashMap<>();
example.removeIf(s -> temp.merge(s, 1, Integer::sum)!=2);
// example output
example.forEach(System.out::println);// prints bar baz
The solution above keeps only one copy for each string having multiple occurrences while removing all strings having no duplicates. If you want to keep all duplicates and just remove those string not having duplicates, there is no way around determining the duplicate status first.
// same example input as above
// actual operation
Map<String,Boolean> temp = new HashMap<>();
example.forEach(s -> temp.merge(s, true, (a,b) -> false));
example.removeIf(temp::get);
// example output
example.forEach(System.out::println);// prints bar baz bar bar baz
Here, the temporary map can be created with a Stream operation with the same logic:
Map<String,Boolean> temp = example.stream()
.collect(Collectors.toMap(Function.identity(), s -> true, (a,b) -> false));
example.removeIf(temp::get);
answered Dec 2 '18 at 21:56
HolgerHolger
163k23231438
163k23231438
add a comment |
add a comment |
The other way would be like this. after groupBy then remove entry with value=1;
result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.values().removeIf(v->v.intValue() == 1);
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.
– nullpointer
Dec 2 '18 at 21:16
4
@nullpointer there is no difference betweenresult.values().removeIf(v -> == 1)
andresult.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.
– Holger
Dec 2 '18 at 21:44
add a comment |
The other way would be like this. after groupBy then remove entry with value=1;
result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.values().removeIf(v->v.intValue() == 1);
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.
– nullpointer
Dec 2 '18 at 21:16
4
@nullpointer there is no difference betweenresult.values().removeIf(v -> == 1)
andresult.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.
– Holger
Dec 2 '18 at 21:44
add a comment |
The other way would be like this. after groupBy then remove entry with value=1;
result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.values().removeIf(v->v.intValue() == 1);
The other way would be like this. after groupBy then remove entry with value=1;
result = list.stream()
.collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
result.values().removeIf(v->v.intValue() == 1);
answered Dec 2 '18 at 20:55
Hadi JHadi J
10.2k31744
10.2k31744
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.
– nullpointer
Dec 2 '18 at 21:16
4
@nullpointer there is no difference betweenresult.values().removeIf(v -> == 1)
andresult.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.
– Holger
Dec 2 '18 at 21:44
add a comment |
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.
– nullpointer
Dec 2 '18 at 21:16
4
@nullpointer there is no difference betweenresult.values().removeIf(v -> == 1)
andresult.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.
– Holger
Dec 2 '18 at 21:44
1
1
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.– nullpointer
Dec 2 '18 at 21:16
result.entrySet().removeIf(v -> v.getValue() == 1); Set<String> res = result.keySet();
would be better I believe.. you can remove the entry instead of removing a value specifically from a list of values.– nullpointer
Dec 2 '18 at 21:16
4
4
@nullpointer there is no difference between
result.values().removeIf(v -> == 1)
and result.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.– Holger
Dec 2 '18 at 21:44
@nullpointer there is no difference between
result.values().removeIf(v -> == 1)
and result.entrySet().removeIf(v -> v.getValue() == 1)
, except that the latter is more verbose. Both variants iterate over the map and remove matching entries.– Holger
Dec 2 '18 at 21:44
add a comment |
A simpler way to find that out could be
List<String> recurringItems = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toList());
Since for items occurring more than once, lastIndex wouldn't be equal to the first index.
Alternatively, you can use Collectors.toSet()
to ensure the items are listed only once in case you are not interested in their order of recurrence.
Set<String> recurringItemsOnce = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toSet());
Or using Collections.frequency
as:
Set<String> recurringItems = list.stream()
.filter(item -> Collections.frequency(list, item) >= 2)
.collect(Collectors.toSet());
this would retrieve duplicate items, e.g. if our list wasArrays.asList("1","2","3","1","56","4","4")
then as a result you'd have[1, 1, 4, 4]
instead of[1, 4]
which of course you could solve by adding adistinct
call after thefilter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.
– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the itemsdistinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.
– nullpointer
Dec 2 '18 at 20:28
3
Simpler in source code, but horrible regarding performance. The OP's original approach usinggroupingBy
as starting point is much preferable.
– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
indexOf
andlastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case offrequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.
– Holger
Dec 2 '18 at 21:40
|
show 2 more comments
A simpler way to find that out could be
List<String> recurringItems = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toList());
Since for items occurring more than once, lastIndex wouldn't be equal to the first index.
Alternatively, you can use Collectors.toSet()
to ensure the items are listed only once in case you are not interested in their order of recurrence.
Set<String> recurringItemsOnce = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toSet());
Or using Collections.frequency
as:
Set<String> recurringItems = list.stream()
.filter(item -> Collections.frequency(list, item) >= 2)
.collect(Collectors.toSet());
this would retrieve duplicate items, e.g. if our list wasArrays.asList("1","2","3","1","56","4","4")
then as a result you'd have[1, 1, 4, 4]
instead of[1, 4]
which of course you could solve by adding adistinct
call after thefilter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.
– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the itemsdistinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.
– nullpointer
Dec 2 '18 at 20:28
3
Simpler in source code, but horrible regarding performance. The OP's original approach usinggroupingBy
as starting point is much preferable.
– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
indexOf
andlastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case offrequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.
– Holger
Dec 2 '18 at 21:40
|
show 2 more comments
A simpler way to find that out could be
List<String> recurringItems = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toList());
Since for items occurring more than once, lastIndex wouldn't be equal to the first index.
Alternatively, you can use Collectors.toSet()
to ensure the items are listed only once in case you are not interested in their order of recurrence.
Set<String> recurringItemsOnce = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toSet());
Or using Collections.frequency
as:
Set<String> recurringItems = list.stream()
.filter(item -> Collections.frequency(list, item) >= 2)
.collect(Collectors.toSet());
A simpler way to find that out could be
List<String> recurringItems = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toList());
Since for items occurring more than once, lastIndex wouldn't be equal to the first index.
Alternatively, you can use Collectors.toSet()
to ensure the items are listed only once in case you are not interested in their order of recurrence.
Set<String> recurringItemsOnce = list.stream()
.filter(item -> list.lastIndexOf(item) != list.indexOf(item))
.collect(Collectors.toSet());
Or using Collections.frequency
as:
Set<String> recurringItems = list.stream()
.filter(item -> Collections.frequency(list, item) >= 2)
.collect(Collectors.toSet());
edited Dec 2 '18 at 20:58
answered Dec 2 '18 at 20:06
nullpointernullpointer
46.2k1198188
46.2k1198188
this would retrieve duplicate items, e.g. if our list wasArrays.asList("1","2","3","1","56","4","4")
then as a result you'd have[1, 1, 4, 4]
instead of[1, 4]
which of course you could solve by adding adistinct
call after thefilter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.
– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the itemsdistinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.
– nullpointer
Dec 2 '18 at 20:28
3
Simpler in source code, but horrible regarding performance. The OP's original approach usinggroupingBy
as starting point is much preferable.
– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
indexOf
andlastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case offrequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.
– Holger
Dec 2 '18 at 21:40
|
show 2 more comments
this would retrieve duplicate items, e.g. if our list wasArrays.asList("1","2","3","1","56","4","4")
then as a result you'd have[1, 1, 4, 4]
instead of[1, 4]
which of course you could solve by adding adistinct
call after thefilter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.
– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the itemsdistinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.
– nullpointer
Dec 2 '18 at 20:28
3
Simpler in source code, but horrible regarding performance. The OP's original approach usinggroupingBy
as starting point is much preferable.
– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
indexOf
andlastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case offrequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.
– Holger
Dec 2 '18 at 21:40
this would retrieve duplicate items, e.g. if our list was
Arrays.asList("1","2","3","1","56","4","4")
then as a result you'd have [1, 1, 4, 4]
instead of [1, 4]
which of course you could solve by adding a distinct
call after the filter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.– Aomine
Dec 2 '18 at 20:23
this would retrieve duplicate items, e.g. if our list was
Arrays.asList("1","2","3","1","56","4","4")
then as a result you'd have [1, 1, 4, 4]
instead of [1, 4]
which of course you could solve by adding a distinct
call after the filter
. on another note, it would be sufficient to keep it as is if the OP wants to get the occurrence of a particular number in the list which requires some additional searching... so ultimately it might be better to proceed with OP's approach.– Aomine
Dec 2 '18 at 20:23
@Aomine Indeed, if the eventual result is desired to just have the items
distinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.– nullpointer
Dec 2 '18 at 20:28
@Aomine Indeed, if the eventual result is desired to just have the items
distinct
would help. Otherwise, if the sequence in which the duplicates occur matters, this can still be used. Added both for completeness.– nullpointer
Dec 2 '18 at 20:28
3
3
Simpler in source code, but horrible regarding performance. The OP's original approach using
groupingBy
as starting point is much preferable.– Holger
Dec 2 '18 at 21:20
Simpler in source code, but horrible regarding performance. The OP's original approach using
groupingBy
as starting point is much preferable.– Holger
Dec 2 '18 at 21:20
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
@Holger Can you shed some details over the horrible regarding performance part. SInce I was considering that collecting to a Map using a stream and then performing operations would still be equal in performance.
– nullpointer
Dec 2 '18 at 21:32
4
4
indexOf
and lastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case of frequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.– Holger
Dec 2 '18 at 21:40
indexOf
and lastIndexOf
are linear searches. You can even predict, that for unique elements, all elements of the list will be traversed when searching once from the beginning and once from the end, and you are repeating this for every element, so the worst case of your operation will be n×n. In case of frequency
, which counts all occurrences, it will always be n×n. Whereas the filling of the map will always be n operations, even if hash operation are more costly and it bears allocations, but that's a fixed constant factor, not growing with the number of elements.– Holger
Dec 2 '18 at 21:40
|
show 2 more comments
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%2f53584012%2ffind-only-repeated-string-attributes-in-list-with-java-8%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