Подтвердить что ты не робот

Вычитание одного массива из другого массива

У меня есть два 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;
4b9b3361

Ответ 1

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

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

Ответ 2

Есть ли причина, по которой вы не можете просто использовать 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]"

Ответ 3

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

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

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

Из Apache Commons Collections

Ответ 4

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) тем, что количество List.removeAll(Collection) соблюдается; если list1 содержит два вхождения null а list2 содержит только одно вхождение, то возвращенный список будет по-прежнему содержать одно вхождение.

Ответ 5

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

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

Ответ 6

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

List resultList = ListUtils.subtract(list, list2);

Ответ 7

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

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

Ответ 8

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

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

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

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

[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]