在迭代

时间:2018-04-16 11:25:18

标签: java collections iterator

我想计算元素数量,如果符合标准则删除一些元素。删除使用collect和removeAll不起作用,因为它删除所有相同的元素,我想删除范围不是全部。 我尝试使用sublist.clear()但是我得到了ConcurrentModificationException,即使我使用它.remove()。

public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
    int writelndex = 0, count=1;
    List<List<Integer>> toRemove = new ArrayList<>();

    for (int i = 1; i < sortedArr.size(); ++i) {

        if (sortedArr.get(i-1).equals(sortedArr.get(i))) {
            count++;
        } else {
            if(count == m) {
                int nCopies = Math.min(2,m);
                List<Integer> c = sortedArr.subList(writelndex + nCopies, i);
                toRemove.add(c);
            }
            count = 1;
            writelndex = i;
        }
    }

    Iterator<List<Integer>> iterator = toRemove.iterator();
    while (iterator.hasNext()) {
        List<Integer> integers = iterator.next();
        iterator.remove();
        integers.clear();
    }
    return sortedArr;
}

编辑:添加一个例子:
假设我们有以下列表:(1,2,2,2,3,3,3,4,4,4,5,5)和m = 3.这意味着所有出现m次的数字都应该发生2次(Math.min(2,3))。所以预期的结果是(1,2,2,2,3,3,3,4,4,5,5)。

编辑2:@ShubhenduPramanik非常优雅地解决了这个任务。 但是,我仍然不清楚为什么抛出ConcurrentModificationException,即使我使用的是iterator.remove(),如何在迭代它时从列表中删除子列表。

3 个答案:

答案 0 :(得分:2)

如果我正确理解了任务,那么算法

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.List;

public class Test {

    public static void main(String[] args) throws IOException {

        int m = 3;

        BufferedReader reader = new BufferedReader(
                new InputStreamReader(System.in));

        int numbers;

        List<Integer> sortedList = new ArrayList<>();

        // Fill in the list with values
        for (int i = 0; i < 13; i++) {
            numbers = Integer.parseInt(reader.readLine());
            sortedList.add(numbers);
        }

        System.out.println(controlOccurrences(sortedList, m));

    }

    public static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {

        int count= 1;


        for (int i = 0; i < sortedArr.size(); i++) {

            for (int j = 0; j < sortedArr.size(); j++) {

                if (sortedArr.get(i).equals(sortedArr.get(j)) && i != j) {

                  count += 1;

                }

            }

            if (count == m) {
                sortedArr.remove(i);
                count = 1;
            } else {
                count = 1;
            }

        }

        return sortedArr;
    }

}

答案 1 :(得分:2)

希望这会有所帮助:

    static List<Integer> controlOccurrences(List<Integer> sortedArr, int m) {
            //make the count of each element
            Map<Integer, Long> result = sortedArr.stream()
                    .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));


            for (Map.Entry<Integer, Long> entry : result.entrySet()) {
                if (entry.getValue() == m) {
                    // Here 2 is hard coded. You can make a variable and pass it to the method with a parameter
                    for (int i = 0; i < m - 2; i++) 
                    {
                        sortedArr.remove(entry.getKey());
                    }
                }
            }

            return sortedArr;
        }

N.B: 此代码并不完美,因为我假设m>=2

答案 2 :(得分:2)

要获得最优化的解决方案,您应该: 1.建立要删除的值的索引列表(或集) 2.将原始列表的值移动到新列表中,但列出的索引除外 3.返回新列表。

这样,您的算法复杂度为O(2n),比以前的答案都更优化。另外,您保持给定列表不变(可根据您的执行上下文推荐)。最后一个优点是,副本是受欢迎的,因为列表上的每个删除调用都可能很重(删除索引后的内部对象被移动到左侧:部分隐藏浏览-_-)

我不会直接给你一个有效的代码,让你练习;)。

注意:您的用例过于复杂,但您应该查看数组列表API的List.removeIf()代码,这是非常优化的。这是一篇关于它的文章:advantages of removeIf method