Java 8 Streams : get non repeated counts

前端 未结 5 1706
南方客
南方客 2021-01-18 11:54

Here is the SQL version for the input and output :

     with tab1 as (

        select 1 as id from dual union all
        select 1 as id from dual union all         


        
相关标签:
5条回答
  • 2021-01-18 12:22
    long result = myList.stream()
             .collect(Collectors.groupingBy(
                       Function.identity(),
                      Collectors.counting()))
             .entrySet()
             .stream()
             .filter(entry -> entry.getValue() == 1)
             .map(Entry::getKey)
             .count();
    

    Well you collect all the elements to a Map<Integer, Long>, where the key is the value itself, and value is how many times it is repeated. Later we stream the entry set from that resulting map and filter only those entries that that have a count of 1 (meaning they are not repeated), later we map to Entry::getKey - to get that value from the List and count.

    0 讨论(0)
  • 2021-01-18 12:23

    You may do it like so,

    Map<Integer, Long> countByNumber = myList.stream()
        .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
    List<Integer> uniqueNumbers = myList.stream()
        .filter(n -> countByNumber.get(n) == 1)
        .collect(Collectors.toList());
    

    First create a map using the value and the number of occurences. Then iterate over the List of numbers, get the occurences from the map for each number. If the number of occurences is 1, then collect it into a separate container.

    If you want to do it in one go, here it is.

    List<Integer> uniqueNumbers = myList.stream()
        .collect(Collectors.collectingAndThen(Collectors.groupingBy(Function.identity(), 
            Collectors.counting()),
        m -> myList.stream().filter(n -> m.get(n) == 1).collect(Collectors.toList())));
    
    0 讨论(0)
  • 2021-01-18 12:30

    For completeness, here's a Java 8 way which doesn't make use of streams:

    Map<Integer, Long> frequencyMap = new LinkedHashMap<>(); // preserves order
    
    myList.forEach(element -> frequencyMap.merge(element, 1L, Long::sum)); // group, counting
    
    frequencyMap.values().removeIf(count -> count > 1); // remove repeated elements
    
    Set<Integer> nonRepeated = frequencyMap.keySet(); // this is your result
    

    This uses Map.merge to fill the map with the count of each element. Then, Collection.removeIf is used on the values of the map, in order to remove the entries whose value is greater than 1.

    I find this way much more compact and readable than using streams.

    0 讨论(0)
  • 2021-01-18 12:37

    An alternative is to filter repeated elements out of the list but it's not very efficient so I would only use it if the list is small:

    List<Integer> result = myList.stream()
                                 .filter(i -> Collections.frequency(myList, i) == 1)
                                 .collect(toList());
    
    0 讨论(0)
  • 2021-01-18 12:45

    Another option for you to consider:

        //Create a map where the key is the element you want to count and the value is the actual count
        Map<Integer, Long> countByItem = myList.stream()
            .collect(Collectors.groupingBy(
                    Function.identity(), //the function that will return the key
                    Collectors.counting())); //the function that will actually count the occurences
    
        //Once you have that map, all you need to do is filter for the registers with count == 1
        List<Integer> result = countByItem.entrySet().stream()
            .filter(entry -> entry.getValue() == 1)
            .map(Map.Entry::getKey)
            .collect(Collectors.toList());
    
    0 讨论(0)
提交回复
热议问题