使用Collections.frequency()打印某些值

时间:2017-11-17 15:06:53

标签: java collections java-8 java-stream

我有一个数组如下:

int[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};

我想要做的是找到重复的值,并打印出来。

所以我这样做的方法是转换为ArrayList,然后转换为Set并使用stream上的Set

ArrayList<Integer> list = new ArrayList<>(array.length);
for (int i = 0; i < array.length; i++) {
    list.add(array[i]);
}

Set<Integer> dup = new HashSet<>(list);

然后我使用stream循环浏览并使用Collections.frequency打印值。

dup.stream().forEach((key) -> {
            System.out.println(key + ": " + Collections.frequency(list, key));
        });

当然,即使计数为1,也会将它们全部打印出来。

我想加入if(key > 1),但这是我想要的价值而不是关键。

如何才能使此实例中的值仅在value > 2

的位置打印

我可能会投入:

int check = Collections.frequency(list, key);
            if (check > 1) {

但是这会在Collections.frequency(list, key)中复制stream并且非常丑陋

10 个答案:

答案 0 :(得分:7)

您可以使用filter仅获取大于2的值:

dup.stream()
       .filter(t -> Collections.frequency(list, t) > 2)
       .forEach(key -> System.out.println(key + ": " + Collections.frequency(list, key)));

结果你的情况是:

11: 4

修改

另一种解决方案:

无需使用SetCollections.frequency即可使用:

Integer[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};
Arrays.stream(array).collect(Collectors.groupingBy(p -> p, Collectors.counting()))
        .entrySet().stream().filter(t -> t.getValue() > 1)
        .forEach(key -> System.out.println(key.getKey() + ": " + key.getValue()));

输出

48: 2
17: 2
11: 4

答案 1 :(得分:4)

完整示例没有在循环中初始化dup并为每个唯一元素调用Collections.frequency一次:

Integer[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};
List<Integer> list = Arrays.asList(array);
Arrays.stream(array).collect(Collectors.toSet())
  .stream()
  .map(v -> new SimpleEntry<>(v, Collections.frequency(list, v)))
  .filter(v -> v.getValue() > 1)
  .forEach(v -> System.out.println(v.getKey() + ":" + v.getValue()));

答案 2 :(得分:2)

这应该有效:

int[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};

List<Integer> list = Arrays.stream(array).boxed().collect(Collectors.toList());

// print values appearing more than once
list.stream().filter(i -> Collections.frequency(list, i) >1)
        .collect(Collectors.toSet()).forEach(System.out::println);

会打印:

48  
17  
11  

如果你也希望得到这样的事情:

int[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};

List<Integer> list = Arrays.stream(array).boxed().collect(Collectors.toList());

list.stream()
    .filter(i -> Collections.frequency(list, i) >1)
    .collect(Collectors.toMap(identity(), v -> 1, Integer::sum))
    .forEach((x, y) -> System.out.println("Key: " + x +", occurence: "+ y));

打印

Key: 48, occurence: 2
Key: 17, occurence: 2
Key: 11, occurence: 4

答案 3 :(得分:2)

package various;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Set;

public class Frequency {
    public static void main(String[] args) {
        int[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};
        ArrayList<Integer> list = new ArrayList<>(array.length);
        for (int i = 0; i < array.length; i++) {
            list.add(array[i]);
        }

        Set<Integer> dup = new HashSet<>(list);

        dup.stream().forEach((key) -> {
            System.out.print((Collections.frequency(list, key) > 2) ? key + ": " + Collections.frequency(list, key) +"\n" : "");
        });
    }
}

输出:

11: 4

答案 4 :(得分:2)

HashMap<Integer, Integer> hashmap = new HashMap<>();
for (int i : array) {
    if (hashmap.containsKey(i)) {
        hashmap.put(i, hashmap.get(i) + 1);
    } else {
        hashmap.put(i, 1);
    }
}

存储值及其频率。

{48=2, 17=2, 33=1, 18=1, 22=1, 11=4, 29=1, 14=1}

编辑:如果要打印重复项;

hashmap.entrySet().stream().filter((entry) -> ((int) entry.getValue() >= 2)).forEach((entry) -> {
    System.out.println(entry.getKey() + ":" + entry.getValue());
});

给你:

48:2
17:2
11:4

答案 5 :(得分:2)

为了实现所需的功能,我们可以促进Java Streams,特别是Stream.collect method

<R> R collect(Supplier<R> supplier,
    BiConsumer<R,? super T> accumulator,
    BiConsumer<R,R> combiner)

请考虑以下草案实施:

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;
import java.util.stream.Collectors;

public class Program {
    public static void main(final String[] args) {
        // Input.
        final int[] inputArray = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};

        // Processing.
        final DuplicateCounter<Integer> duplicateCounter = Arrays.stream(inputArray)
            .collect(
                DuplicateCounter<Integer>::new,
                DuplicateCounter<Integer>::accept,
                DuplicateCounter<Integer>::combine
            );

        // Output.
        System.out.println(duplicateCounter.getDuplicateCountMap());
    }

    private static final class DuplicateCounter<T> implements Consumer<T> {
        private final Map<T, Integer> countMap = new HashMap<>();

        public void accept(final T obj) {
            this.incrementCounter(obj, 1);
        }

        public void combine(final DuplicateCounter<T> other) {
            other.countMap.entrySet()
                .forEach(entry -> this.incrementCounter(entry.getKey(), entry.getValue()));
        }

        public Map<T, Integer> getDuplicateCountMap() {
            return this.countMap.entrySet()
                .stream()
                .filter(entry -> entry.getValue() > 1)
                .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
        }

        private void incrementCounter(final T obj, int increment) {
            final Integer counter = this.countMap.getOrDefault(obj, 0);
            this.countMap.put(obj, counter + increment);
        }
    }
}

输出:

  

{48 = 2,17 = 2,11 = 4}

其他参考资料:

  1. Reduction (The Java™ Tutorials > Collections > Aggregate Operations)
  2. Java 8 Streams - collect vs reduce

答案 6 :(得分:2)

还有另一种功能方式:

HashMap<Integer, Long> result = Arrays.stream(array)
            .boxed()
            .collect(Collectors.collectingAndThen(Collectors.groupingBy(
                    Function.identity(),
                    HashMap::new,
                    Collectors.counting()),
                    map -> {
                        map.entrySet().removeIf(x -> x.getValue() == 1);
                        return map;
                    }));

接受接受的答案 - 这可能是最糟糕的,就像对每个元素使用Collections.frequency的每一个建议一样(即使是唯一的)

答案 7 :(得分:2)

Collections.frequency的问题是它必须遍历所有集合才能找到给定元素的频率。如果你为集合的每个元素执行,那么你的解决方案是O(n^2),即非常低效,因为处理时间会随着集合中元素数量的平方而增加。 / p>

相反,您可以使用流创建一个计算每个元素出现次数的地图,如下所示:

int[] array = {11, 14, 17, 11, 48, 33, 29, 11, 17, 22, 11, 48, 18};

Map<Integer, Long> occurrences = Arrays.stream(array)
    .boxed()
    .collect(Collectors.groupingBy(
        Function.identity(), 
        Collectors.counting()));

现在,如果您只想保留多次出现的值,您只需删除值等于1的地图条目:

occurrences.values().removeIf(v -> v == 1);

最后,如果你打印地图:

System.out.println(occurrences);

您将获得以下输出:

{48=2, 17=2, 11=4}

或者,以您期望的格式获得输出:

occurrences.forEach((k, v) -> System.out.println(k + ": "+ v));

另一种方式,更短,没有流的开销:

Map<Integer, Long> occurrences = new HashMap<>();
for (int n : array) occurrences.merge(n, 1L, Long::sum);

然后,删除前面显示的唯一元素的条目:

occurrences.values().removeIf(v -> v == 1);

答案 8 :(得分:1)

您可以使用过滤器:

dup.stream().filter(key -> Collections.frequency(list,key)>2).forEach(System.out::println);

答案 9 :(得分:1)

您根本不必将其转换为ArrayList。看看这个:

HashSet<Integer> set = new HashSet<Integer>();
for (int i = 0; i < array.length; i++) {
    if(set.contains(array[i]))
        System.out.println(array[i]);
    else
        set.add(array[i]);
}