Java 8 删除值以仅保留N个引用

Java 8 删除值以仅保留N个引用,java-8,java-stream,Java 8,Java Stream,我今天做了一些《暗战》中的卡塔。我必须编写一个函数,从数组中只保留N个相同的元素,例如: {1,2,3,4,1}, N=1 -> {1,2,3,4} {2,2,2,2}, N=2 -> {2,2} 我使用streams提出了该解决方案: public static int[] deleteNth(int[] elements, int maxOcurrences) { List<Integer> ints = Arrays.stream(elements)

我今天做了一些《暗战》中的卡塔。我必须编写一个函数,从数组中只保留N个相同的元素,例如:

{1,2,3,4,1}, N=1 -> {1,2,3,4}
{2,2,2,2}, N=2 -> {2,2}
我使用streams提出了该解决方案:

 public static int[] deleteNth(int[] elements, int maxOcurrences) {
    List<Integer> ints = Arrays.stream(elements)
                               .boxed()
                               .collect(Collectors.toList());
    return ints.stream().filter(x -> Collections.frequency(ints, x) <= maxOcurrences)
        .mapToInt(Integer::intValue)
        .toArray();
}
public static int[]deleteNth(int[]元素,int maxoccurrences){
List ints=Arrays.stream(元素)
.boxed()
.collect(Collectors.toList());

return ints.stream().filter(x->Collections.frequency(ints,x)实际上您排除了优于
maxOcurrences
值的元素:

.filter(x -> Collections.frequency(ints, x) <= maxOcurrences)
输出:

[1,2,3,4]

[2,2]


我发现完成手头任务的解决方案如下:

public static int[] deleteNth(int[] elements, int maxOccurrences) {
    return Arrays.stream(elements)
                 .boxed()
                 .collect(Collectors.groupingBy(Function.identity(), 
                        LinkedHashMap::new,
                        Collectors.counting()))
                 .entrySet()
                 .stream()
                 .flatMapToInt(entry ->
                    IntStream.generate(entry::getKey)
                             .limit(Math.min(maxOccurrences, entry.getValue())))
                 .toArray();
}

我们首先对元素进行分组,然后应用一个
Collectors.counting()
作为下游收集器,获取给定元素的计数。完成后,我们只需将给定数量的
n
映射多次,然后使用
toArray
急切操作收集到一个数组。

我认为这是一个不使用流的好例子。流并不总是有状态操作的最佳方法这涉及到许多人

但是这是绝对可以做到的,而且这个问题特别针对流,所以您可以使用以下内容


使用forEachOrdered

您可以使用
forEachOrdered
,以确保顺序(显然,流必须是顺序的)

这个
收集器
创建一个
数组列表
,当添加新元素时,检查是否满足
maxOcurrences
,如果不满足,则添加元素。如前所述,在下面的回答中,根本不调用组合器。这比
n^2
好一点


可以找到为什么在序列流中不调用组合器方法的更多信息。

这不能保证顺序,这可能是必需的。@JoseDaSilva您有它。不,我是指元素的顺序,例如
n=2
{2,3,2,2,2}
,这里的输出应该是
{2,2,3}
,但应该是
{2, 3, 2}
?,我们还不知道。我要保存这个简洁的收集技巧,谢谢你的解决方案。基本上,你是在检查列表中的元素是否少于N个,并在为真时添加它们,对吗?你能解释一下为什么我的方法不起作用吗?你的方法不起作用,因为你检查的是所有元素,而不仅仅是你之前拥有的元素这一点。例如,使用
{2,2,2,2}
,如果你对照孔列表进行检查,你会得到4次重复,并且在过滤器中你会将它们全部丢弃。如果你改为从
{}
开始,然后添加
2
,第一次检查重复是
0
{2}
,然后添加另一次
2
,检查重复是
1
{2,2}
,最后要添加另一个
2
,首先检查重复
2是的,超出限制的事件应被丢弃,并且应保持顺序
public static int[] deleteNth(int[] elements, int maxOccurrences) {
    return Arrays.stream(elements)
                 .boxed()
                 .collect(Collectors.groupingBy(Function.identity(), 
                        LinkedHashMap::new,
                        Collectors.counting()))
                 .entrySet()
                 .stream()
                 .flatMapToInt(entry ->
                    IntStream.generate(entry::getKey)
                             .limit(Math.min(maxOccurrences, entry.getValue())))
                 .toArray();
}
public static int[] deleteNth(int[] elements, int maxOcurrs) {
    List<Integer> list = new ArrayList<>();
    Arrays.stream(elements).forEachOrdered(elem -> {
        if (Collections.frequency(list, elem) < maxOcurrs) list.add(elem);
    });
    return list.stream().mapToInt(Integer::intValue).toArray();
}
public static int[] deleteNth(int[] elements, int maxOcurrs) {
    return Arrays.stream(elements).boxed()
            .collect(() -> new ArrayList<Integer>(),
                    (list, elem) -> {
                        if (Collections.frequency(list, elem) < maxOcurrs) list.add(elem);
                    },
                    (list1, list2) -> { 
                        throw new UnsupportedOperationException("Undefined combiner"); 
                    })
            .stream()
            .mapToInt(Integer::intValue)
            .toArray();
}