У меня метод, который сливает элементы коллекции, если поля этих элементов, подходят под определенные условия. И при определенных условиях какие-то из элементов надо удалить прямо на ходу, но при использовании циклов foreach
я не могу использовать удаление из коллекции так как натыкаюсь на ConcurrentModificationException
. И мне приходится ходить по коллекции двойным циклом используя счетчик, и все время дергать методы get(...)
.
Проблема заключается в том что операция remove(...)
для ArrayList
очень дорогая так как надо сдвигать все элементы. А операция get(...)
дорогая для LinkedList
. Таким образом получается что мне совершенно необходимо избавится либо от одной операции, либо от другой.
И я попал в не приятную вилку: беру LinkedList
, и убираю get()
- получаю ConcurrentModificationException
, беру ArrayList
из-за метода remove(...)
теряю всю производительность.
Помогите пожалуйста выйти из этой ситуации, так что-бы не терять производительность.
Вот мой код:
@Override
public Collection<Order> automaticDeals(List<Order> orders) {
for (int i = 0; i < orders.size(); i++) {
for (int j = 1 ;j < orders.size(); j++) {
List<Order> forDelete = deal(orders.get(i), orders.get(j));
for (Order order : forDelete) {
orders.remove(order);
}
}
}
return orders;
}
private List<Order> deal(Order fstOrder, Order scdOrder) {
List<Order> ordersForDelete = new LinkedList<>();
if (dealIsImpossible(fstOrder, scdOrder)) {
return ordersForDelete;
}
if (fstOrder.getVolume() < scdOrder.getVolume()) {
int volume = scdOrder.getVolume() - fstOrder.getVolume();
scdOrder.setVolume(volume);
ordersForDelete.add(fstOrder);
} else if (fstOrder.getVolume() > scdOrder.getVolume()) {
int volume = fstOrder.getVolume() - scdOrder.getVolume();
fstOrder.setVolume(volume);
ordersForDelete.add(scdOrder);
} else if (fstOrder.getVolume() == scdOrder.getVolume()) {
ordersForDelete.add(fstOrder);
ordersForDelete.add(scdOrder);
}
return ordersForDelete;
}
как я понял, нужна операция distinct по особому полю. Это можно выполнить с помощью java 8 stream api с реализацией своего предиката.
public class Order {
private int volume;
private int sec;
public Order(int volume) {
this.volume = volume;
}
public int getVolume() {
return volume;
}
@Override
public String toString() {
return "Order{" +
"volume=" + volume +
'}';
}
}
public static void main(String[] args) {
List<Order> collect = new ArrayList<Order>() {{
add(new Order(4));
add(new Order(1));
add(new Order(1));
add(new Order(8));
add(new Order(1));
add(new Order(2));
}};
List<Order> res = collect.stream().filter(distinctByKey(f -> f.getVolume())).collect(Collectors.toList());
res.forEach(System.out::println);
}
public static <T> Predicate<T> distinctByKey(Function<? super T, ?> keyExtractor) {
Map<Object,Boolean> seen = new ConcurrentHashMap<>();
return t -> seen.putIfAbsent(keyExtractor.apply(t), Boolean.TRUE) == null;
}
результат выполнения:
Order{volume=4}
Order{volume=1}
Order{volume=8}
Order{volume=2}
P.s можно использовать parallel()
для ускорения операций
вдохновился источником
Кофе для программистов: как напиток влияет на продуктивность кодеров?
Рекламные вывески: как привлечь внимание и увеличить продажи
Стратегії та тренди в SMM - Технології, що формують майбутнє сьогодні
Выделенный сервер, что это, для чего нужен и какие характеристики важны?
Современные решения для бизнеса: как облачные и виртуальные технологии меняют рынок
В сервисе у меня есть таймер по окончанию которой идет запрос к серверу:
Как сделать слушатель для графики OnDraw в MainActivity на нажатие?
У меня есть mysql сервер и 2 приложения: web (сайт, grails 3) и android приложениеБаза данных содержит расписание матчей
Как в одном из нескольких фрагментов добавить постоянно отображающийся клавиатуру