Вычитание одного массива из другого массива
У меня есть два 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;
Ответы
Ответ 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]