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

у меня есть два arrayLists, и я пытаюсь "вычесть" один 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 и они пресортированы, я также не знаю хэша или 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;

8 ответов


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

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


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

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

попробуйте использовать метод вычитания org.апаш.палата общин.коллекции.Класс CollectionUtils.

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

CollectionUtils.вычесть (java.утиль.Коллекция a, java.утиль.Коллекция b)

с Коллекции Apache Commons


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

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


вы можете использовать org.апаш.палата общин.коллекции.ListUtils и сделать все, что вы хотите только одну строку =)

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

на всякий случай, если вы планируете использовать Java8, вы также можете использовать потоки:

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) или поток с фильтра.


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

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


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

вычесть (a, b)

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

a содержит

[1, 3]

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

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

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

разница в removeAll ()

[1,2,2,3].removeAll([1,2,3]) //is empty
[1,2,3].forEach((i)->[1,2,2,3].remove(i)); //a is [2]