Find only repeated String attributes in list with Java 8











up vote
10
down vote

favorite
1












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()));









share|improve this question




























    up vote
    10
    down vote

    favorite
    1












    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()));









    share|improve this question


























      up vote
      10
      down vote

      favorite
      1









      up vote
      10
      down vote

      favorite
      1






      1





      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()));









      share|improve this question















      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






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Dec 2 at 19:57









      Aomine

      36.1k62961




      36.1k62961










      asked Dec 2 at 19:51









      Rishabh Chaturvedi

      513




      513
























          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());





          share|improve this answer























          • 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 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




















          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);





          share|improve this answer




























            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);





            share|improve this answer

















            • 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 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


















            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());





            share|improve this answer























            • 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






            • 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










            • @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 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











            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',
            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
            });


            }
            });














            draft saved

            draft discarded


















            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








            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());





            share|improve this answer























            • 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 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

















            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());





            share|improve this answer























            • 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 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















            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());





            share|improve this answer














            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());






            share|improve this answer














            share|improve this answer



            share|improve this answer








            edited Dec 2 at 20:37

























            answered Dec 2 at 19:53









            Aomine

            36.1k62961




            36.1k62961












            • 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 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




















            • 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 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


















            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














            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);





            share|improve this answer

























              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);





              share|improve this answer























                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);





                share|improve this answer












                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);






                share|improve this answer












                share|improve this answer



                share|improve this answer










                answered Dec 2 at 21:56









                Holger

                160k23223428




                160k23223428






















                    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);





                    share|improve this answer

















                    • 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 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















                    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);





                    share|improve this answer

















                    • 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 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













                    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);





                    share|improve this answer












                    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);






                    share|improve this answer












                    share|improve this answer



                    share|improve this answer










                    answered Dec 2 at 20:55









                    Hadi J

                    9,68731540




                    9,68731540








                    • 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 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














                    • 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 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








                    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










                    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());





                    share|improve this answer























                    • 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






                    • 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










                    • @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 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















                    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());





                    share|improve this answer























                    • 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






                    • 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










                    • @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 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













                    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());





                    share|improve this answer














                    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());






                    share|improve this answer














                    share|improve this answer



                    share|improve this answer








                    edited Dec 2 at 20:58

























                    answered Dec 2 at 20:06









                    nullpointer

                    38.3k1073146




                    38.3k1073146












                    • 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






                    • 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










                    • @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 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


















                    • 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






                    • 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










                    • @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 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
















                    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


















                    draft saved

                    draft discarded




















































                    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.




                    draft saved


                    draft discarded














                    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





















































                    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







                    Popular posts from this blog

                    Morgemoulin

                    Scott Moir

                    Souastre