【问题标题】:Need to remove elements from an ArrayList of ArrayLists<Double>需要从 ArrayLists<Double> 的 ArrayList 中删除元素
【发布时间】:2019-06-10 11:39:01
【问题描述】:

我有处理 wav 文件并将双精度值(音频样本)集合排序到 ArrayList 的代码,然后将这些 ArrayList 中的每一个排序到 ArrayList 的 ArrayList 中:

ArrayList<Double> sampleEvent = new ArrayList<Double>();

ArrayList<ArrayList<Double>> EventsCollect = new ArrayList<ArrayList<Double>>();

我的代码尝试从集合中删除小于特定大小的 ArrayList。

然而,它似乎所做的只是列表的一半,并没有从集合中删除正确的 ArrayLists。

请看我下面的代码:

for (int loop = 0 ;   loop <  EventsCollect.size(); loop++) {
    if ( EventsCollect.get(loop).size() <  200000) {
         EventsCollect.remove(loop);
    }
}

完成此操作后,ArrayList 仍保留在集合中,大小仅为三位数。

任何有关如何纠正此问题的建议将不胜感激。

【问题讨论】:

  • 你应该遵循 Java 命名约定:变量名是用驼峰命名的,这意味着它们以小写字母开头。所以EventsCollect 应该是eventsCollect
  • 你能描述一下代码应该做什么吗?它应该在什么时候准确删除哪些元素?
  • 请注意,当您从前面删除一个元素时,所有剩余的元素都会移动(更改它们的索引)。所以如果你有(1,2,3,4,5),然后删除第一个元素,然后删除第二个元素,你最终不会得到(3,4,5),而是(2,4,5)
  • 您可能需要查看removeRangetrimToSize 以一次性删除大量元素。
  • 在 ArrayList 中存储大量 Doubles 的内存效率非常,因为这会为每个 double 创建一个对象包装器,使其占用其正常大小的许多倍。使用double[] 可以让您在内存使用方面更进一步。

标签: java arraylist


【解决方案1】:

您的问题是,即使您删除了一个元素,也会增加循环计数器。通过这样做,您可以跳过循环中的一个元素。只需更改您的 if 语句:

    int loop = 0; // loop counter
    while (loop < EventsCollect.size()) {
        if (EventsCollect.get(loop).size() < 200000) {
            EventsCollect.remove(loop);
        }
        else
            loop++;
    }

或者您可以通过 ArrayList 向后循环:

for (int i = EventsCollect.size() - 1; i >= 0; i --){
    if (EventsCollect.get(i).size() > 200000)
        EventsCollect.remove(i);
}

这是可行的,因为您将始终循环遍历数组一段恒定的时间。如果您查看您的代码,EventsCollect.size() 在您删除元素时会发生变化,因此不会循环 通过每一个元素。这应该是您出现问题的提示。

【讨论】:

    【解决方案2】:

    在 java 8 中,您可以尝试使用 lambda 表达式删除 with predicate

        EventsCollect = EventsCollect.stream() 
                   //we want to retain only samples with more than 200_000 count
                   .filter(sampleEvent -> sampleEvent.size() >=  200_000) 
                   //we collect everything that we want back into our EventsCollect list
                   .collect(Collectors.toList()); 
    

    作为旁注,您可能希望将 EventsCollect 重命名为 eventsCollect(小写字母 e)。

    无论如何,只有一半的条目是评估的原因是因为当你 删除一个条目,所有底部都上移一个。这样做的效果是不会评估新移动条目的第一项。

    假设我们有 4 个条目,而 i 当前为 1(指向 100k)

    {230k, 100k, 20k, 122k} 
    

    循环评估并删除 100k

    {230, 20k, 122k}
    

    现在所有值都上移 1,并且 i 递增到 2(指向 122k)。注意 20k 在 1 的位置,现在被跳过了。循环将评估并删除 122k。

    {230, 20k}
    

    要以最少的更改来修复您的代码,您需要进行反向迭代(从最后一个条目到第一个条目)

    for (int loop = EventsCollect.size()-1 ;   loop >=0; loop--) {
        if ( EventsCollect.get(loop).size() <  200000) {
             EventsCollect.remove(loop);
        }
    }
    

    【讨论】:

      猜你喜欢
      • 2013-02-24
      • 2016-07-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-13
      • 2011-06-24
      相关资源
      最近更新 更多