Вопрос:

Вычитание одного arrayList из другого arrayList

java

46579 просмотра

8 ответа

471 Репутация автора

У меня есть два arrayList, и я пытаюсь «вычесть» один arrayList из другого. Например, если у меня есть один arrayList [1,2,3], и я пытаюсь вычесть [0, 2, 4], результирующий arrayList должен быть [1,3].

List<Integer> a = new ArrayList<>(Arrays.asList(1, 2, 3));
List<Integer> b = Arrays.asList(0, 2, 4);
subtract(a,b) // should return [1,3]

Вот мой код

//returns a new IntSet after subtracting a from b
// .minus().toString()
ArrayList<Integer> minusArray = new ArrayList<Integer>();

    minusArray.addAll(array1);

    for(int i =0; i< minusArray.size(); i++){
        for(int j = 0; j < array2.size(); j++){
            if(minusArray.get(i).equals(array2.get(j))){
                minusArray.remove(i);
                if(i == 0){
                    ;
                }
                else if(j == 0){
                    ;
                }
                else{
                    i = 0;
                    j = 0;
                }
            }
            else{}
        }
    }

return minusArray;

Мой код работает в некоторых случаях, например, если arrayList1 = [4,6]и arrayList2 = [6]он даст мне результат [4]. Но если я попробую что-то вроде [1,2,4]и[0,4,8]

Я получаю это исключение:

java.lang.IndexOutOfBoundsException: Index: 2, Size: 2
    at java.util.ArrayList.rangeCheck(Unknown Source)
    at java.util.ArrayList.get(Unknown Source)
    at IntSet.minus(IntSet.java:119)
    at IntSetDriver.main(IntSetDriver.java:62)

Вот код, который я придумал. Я сделал тестовые прогоны через него, и я думаю, что это должно работать. Пользователь вводит эти arrayLists и они предварительно отсортированы, я также не знаю Hash или big-O.

ArrayList<Integer> minusArray = new ArrayList<Integer>();

    minusArray.addAll(array1);

    for(int i =0; i< minusArray.size(); i++){
        for(int j = 0; j < array2.size(); j++){
            if(minusArray.get(i).equals(array2.get(j))){
                minusArray.remove(i);
            }
            else{}
        }
    }

return minusArray;
Автор: Milwaukoholic Источник Размещён: 29.03.2012 08:56

Ответы (8)


3 плюса

22057 Репутация автора

Решение

Ваша проблема в том, что при вызове minusArray.remove (...) вы можете уменьшить размер minusArray. Чтобы это исправить, начните с array.size () - 1 и посчитайте до 0

Проверьте это - даже это не исправит это. Вам нужно изменить порядок ваших петель

Автор: ControlAltDel Размещён: 29.03.2012 08:59

31 плюса

3136 Репутация автора

Попробуйте использовать метод вычитания класса org.apache.commons.collections.CollectionUtils.

Возвращает новую коллекцию, содержащую a - b. Мощность каждого элемента e в возвращенной Коллекции будет равна количеству элементов e в минус количество элементов e в b или ноль, в зависимости от того, что больше.

CollectionUtils.subtract (java.util.Collection a, java.util.Collection b)

Из коллекций Apache Commons

Автор: Hirak Размещён: 29.03.2012 09:02

2 плюса

169 Репутация автора

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

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

Автор: Prethen Размещён: 29.03.2012 09:03

7 плюса

5481 Репутация автора

Обход minusArrayиспользования индекса является одним из способов сделать это, но я предлагаю вам использовать contains(Object)метод, который позволит вам затем использовать remove(Object)для конкретного элемента array2.

Конечно, всегда есть то, removeAll(Collection)что делает почти все, что вам нужно ...

Автор: Yuval Размещён: 29.03.2012 09:03

5 плюса

305 Репутация автора

Вы можете использовать org.apache.commons.collections.ListUtils и сделать все, что вы хотите, в одну строку =)

List resultList = ListUtils.subtract(list, list2);
Автор: Nicolas Размещён: 24.10.2013 07:03

35 плюса

914 Репутация автора

По какой причине вы не можете просто использовать List.removeAll (List)?

    List<Integer> one = new ArrayList<Integer>();
    one.add(1);
    one.add(2);
    one.add(3);
    List<Integer> two = new ArrayList<Integer>();
    two.add(0);
    two.add(2);
    two.add(4);
    one.removeAll(two);
    System.out.println(one);

    result: "[1, 3]"
Автор: Mark Phillips Размещён: 19.04.2014 04:29

2 плюса

2509 Репутация автора

Попробуйте этот ответ, если removeAll() не то, что вы хотите . например, если вас интересует что-то вроде расчета разницы двух списков с дубликатами

вычесть (а, б)

b.forEach((i)->a.remove(i));

a теперь содержит

[1, 3]

Это следует за предложением разработчиков Guava о том, как реализовать вычитание

msgstr "создать ArrayList, содержащий a, а затем вызвать delete для него для каждого элемента в b."

Который ведет себя как эта реализация, используемая в Apache Commons

Разница для удаления All ()

[1,2,2,3].removeAll([1,2,3]) //is empty
[1,2,3].forEach((i)->[1,2,2,3].remove(i)); //a is [2] 
Автор: jschnasse Размещён: 21.03.2018 07:53

11 плюса

13469 Репутация автора

Java 8

Вы также можете использовать потоки:

List<Integer> list1 =  Arrays.asList(1, 2, 3);
List<Integer> list2 =  Arrays.asList(1, 2, 4, 5);
List<Integer> diff = list1.stream()
                          .filter(e -> !list2.contains(e))
                          .collect (Collectors.toList()); // (3)

Этот ответ не манипулирует первоначальным списком. Если намерение состоит в том, чтобы изменить исходный список, то мы можем использовать remove. Также мы можем использовать forEach(метод по умолчанию в Iterator) или поток с фильтром.

Использование ListUtils

Другой вариант - использовать, ListUtilsесли мы используем Apache common:

ListUtils.subtract(list, list2)

Это вычитает все элементы во втором списке из первого списка, помещая результаты в новый список. Это отличается от того, List.removeAll(Collection)что кардинальность соблюдается ; если list1 содержит два вхождения, nullа list2 содержит только одно вхождение, то возвращенный список будет по-прежнему содержать одно вхождение.

Автор: i_am_zero Размещён: 16.04.2018 06:05
Вопросы из категории :
32x32