Нужно удалить элементы из ArrayList из ArrayLists<Double>

У меня есть код, который обрабатывает wav-файлы и сортирует коллекции двойных значений (аудиообразцы) в ArrayList, и каждый из этих ArrayList затем сортируется в ArrayList из ArrayLists:

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

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

У меня есть код, который пытается удалить ArrayLists меньше определенного размера из коллекции.

Однако все, что он делает, это половина списка и не удаляет правильные ArrayLists из коллекции.

Пожалуйста, смотрите мой код ниже:

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

После этого в коллекции остаются ArrayLists, которые имеют размер только трехзначного числа.

Будем очень признательны за любые советы о том, как это исправить.

Вы должны следовать соглашениям об именах Java: имена переменных пишутся в camelCase, это означает, что они начинаются с нижнего регистра. Так что EventsCollect должно быть eventsCollect.

MC Emperor 10.06.2019 01:03

Можете ли вы описать, что должен делать код? Какие элементы он должен удалить точно и когда?

Thilo 10.06.2019 01:48

Обратите внимание, что когда вы удаляете элемент спереди, все оставшиеся элементы смещаются (меняют свой индекс). Итак, если у вас есть (1,2,3,4,5) и вы удалите первый, а затем второй элемент, вы получите НЕ (3,4,5), а (2,4,5).

Thilo 10.06.2019 01:50

Вы можете посмотреть на removeRange или trimToSize, чтобы удалить много элементов за один раз.

Thilo 10.06.2019 01:51

очень неэффективно для памяти хранить большое количество двойников в ArrayList, поскольку это создает оболочку объекта для каждого двойника, что делает его во много раз больше обычного размера. Использование double[] значительно улучшит использование памяти.

Erwin Bolwidt 10.06.2019 04:17

вам нужно сделать обратный цикл (обратный отсчет) при попытке удалить из списка. причина в том, что все более поздние записи сдвигаются вверх. это приводит к тому, что запись пропускается для проверки. в качестве альтернативы вы можете попробовать использовать методы потоков и фильтров (см. мой ответ)

Angel Koh 10.06.2019 05:32
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
6
154
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

Ваша проблема в том, что вы увеличиваете счетчик цикла, даже если удаляете элемент. Делая это, вы пропускаете элемент в цикле. Просто измените оператор 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() изменится, когда вы удалите элементы, поэтому не зацикливаетесь через каждый элемент. Это должно быть вашим сигналом, что что-то не так.

в java 8 вы можете попробовать удалить с помощью предиката, используя лямбда-выражения

    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 записи, и я в настоящее время на 1 (указывает на 100k)

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

цикл оценивает и удаляет 100k

{230, 20k, 122k}

теперь все значения сдвигаются вверх на единицу, а i увеличивается до 2 (указывает на 122k). обратите внимание, что 20k стоит на позиции 1 и теперь пропускается. вместо этого цикл оценит и удалит 122 КБ.

{230, 20k}

чтобы исправить свой код с минимальными изменениями, вам нужно сделать обратную итерацию (от последней записи к первой)

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

Другие вопросы по теме