Find only repeated String attributes in list with Java 8
up vote
10
down vote
favorite
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
New contributor
add a comment |
up vote
10
down vote
favorite
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
New contributor
add a comment |
up vote
10
down vote
favorite
up vote
10
down vote
favorite
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
New contributor
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
New contributor
New contributor
edited Dec 2 at 19:57
Aomine
34.7k62859
34.7k62859
New contributor
asked Dec 2 at 19:51
Rishabh Chaturvedi
513
513
New contributor
New contributor
add a comment |
add a comment |
4 Answers
4
active
oldest
votes
up vote
6
down vote
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 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 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 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 at 21:19
|
show 1 more comment
up vote
6
down vote
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 |
up vote
4
down vote
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 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 at 21:44
add a comment |
up vote
2
down vote
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 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 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 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 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 at 21:40
|
show 2 more comments
4 Answers
4
active
oldest
votes
4 Answers
4
active
oldest
votes
active
oldest
votes
active
oldest
votes
up vote
6
down vote
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 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 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 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 at 21:19
|
show 1 more comment
up vote
6
down vote
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 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 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 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 at 21:19
|
show 1 more comment
up vote
6
down vote
up vote
6
down vote
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 at 20:37
answered Dec 2 at 19:53
Aomine
34.7k62859
34.7k62859
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 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 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 at 21:19
|
show 1 more comment
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.
– nullpointer
Dec 2 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 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 at 21:19
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 at 20:57
I would personally prefer filtering out based on a logic over creating stream twice.
– nullpointer
Dec 2 at 20:57
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
@nullpointer mhmmm.. what do you mean?
– Aomine
Dec 2 at 20:59
list.stream() .filter(x -> list.stream().filter..
was pointing out this.– nullpointer
Dec 2 at 21:00
list.stream() .filter(x -> list.stream().filter..
was pointing out this.– nullpointer
Dec 2 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 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 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 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 at 21:19
|
show 1 more comment
up vote
6
down vote
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 |
up vote
6
down vote
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 |
up vote
6
down vote
up vote
6
down vote
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 at 21:56
Holger
160k23223428
160k23223428
add a comment |
add a comment |
up vote
4
down vote
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 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 at 21:44
add a comment |
up vote
4
down vote
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 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 at 21:44
add a comment |
up vote
4
down vote
up vote
4
down vote
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 at 20:55
Hadi J
9,56731539
9,56731539
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 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 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 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 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 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 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 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 at 21:44
add a comment |
up vote
2
down vote
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 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 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 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 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 at 21:40
|
show 2 more comments
up vote
2
down vote
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 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 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 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 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 at 21:40
|
show 2 more comments
up vote
2
down vote
up vote
2
down vote
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 at 20:58
answered Dec 2 at 20:06
nullpointer
37.9k1072145
37.9k1072145
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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 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 at 21:40
|
show 2 more comments
Rishabh Chaturvedi is a new contributor. Be nice, and check out our Code of Conduct.
Rishabh Chaturvedi is a new contributor. Be nice, and check out our Code of Conduct.
Rishabh Chaturvedi is a new contributor. Be nice, and check out our Code of Conduct.
Rishabh Chaturvedi is a new contributor. Be nice, and check out our Code of Conduct.
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%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