Ideal if you have a set method for volume:
static Collection<Order> mergeOrdersVolumeSet(Collection<Order> orders){ //Мапа на основе которой будем объединять. Ключ - price final Map<Integer,Order> orderMap = new HashMap<>(); //Проходим по старым ордерам orders.forEach(order -> { //Пытаемся по прайсу ордера найти уже существующий final Order o = orderMap.get(order.getPrice()); if (o==null){//Если не нашли - добавляем orderMap.put(order.getPrice(),order); }else {//Иначе, в уже существующем меняем volume o.setVolume(o.getVolume()+order.getVolume()); } }); return orderMap.values(); }
The remaining options make sense if you do not have a volume setter.
You can do without mapy, but I'm not sure that this will be faster:
static Collection<Order> mergeOrders(Collection<Order> orders){ final Collection<Order> result = new ArrayList<>(); //Пока старая коллекция не пуста while (!orders.isEmpty()){ //Использую итератор, т.к. буду удалять из изначальной коллекции. final Iterator<Order> oldOrdersIterator = orders.iterator(); //Получаем первый Ордер final Order firstOrder = oldOrdersIterator.next(); //Одтельно получаем значение кол-ва int volume = firstOrder.getVolume(); //Сразу удаляем его из коллекции oldOrdersIterator.remove(); //Проходим по остальным значениям старой коллекции, если они еще есть while (oldOrdersIterator.hasNext()){ //Получаем текущее final Order oldOrder = oldOrdersIterator.next(); //Если прайс совпадает с первым ордером if (firstOrder.getPrice()==oldOrder.getPrice()){ oldOrdersIterator.remove();//Удаляем его из коллекции volume+=oldOrder.getVolume();//Обновляем актуальное значение кол-ва } } //Если значение кол-ва отличается от начального if (volume!=firstOrder.getVolume()){ //Создаем новый ордер на основе старого прайса и нового кол-ва result.add(new Order(firstOrder.getPrice(),volume)); }else { //Иначе добавляем неизменившийся result.add(firstOrder); } } return result; }
Option with a map:
static Collection<Order> mergeOrdersMap(Collection<Order> orders){ //Можно вместо коллекции ордеров использовать Integer значение, равное сумме volumes, но тут не ясно что быстрее. // Т.к. в такой ситуации придется заново инициализировать каждый ордер Map<Integer,Collection<Order>> mergeMap = new HashMap<>(); //Проходим по всем старым ордерам orders.forEach(order -> { //Пытаемся получить коллекцию ордеров с текущим значением прайса Collection<Order> keyOrders = mergeMap.get(order.getPrice()); if (keyOrders==null){//Если не получили //то кидаем в мапу новый прайс, и с ним ассоциируем новый лист, в котором пока один ордер mergeMap.put(order.getPrice(),new ArrayList<>(Collections.singleton(order))); }else{ //Иначе добавляем новый ордер keyOrders.add(order); } }); //Создаем результирующую коллекцию. Сразу задаем размер как у получившейся мапы. //Т.к. кол-во прайсов и есть кол-во ордеров после объединения final Collection<Order> result = new ArrayList<>(mergeMap.size()); //Проходим по мапе mergeMap.forEach((integer, orders1) -> { //Если размер списка == 1, то значит похожих ордеров не было, и можно добавить прямо этот if (orders1.size()==1){ result.add(orders1.stream().findFirst().get()); }else { //Иначе проходим по коллекции, считаем суммарный volume int vol = 0; for (Order o: orders1){ vol+=o.getVolume(); } //И добавляем новый объект result.add(new Order(integer,vol)); } }); return result; }
Check (The result is the same everywhere):
public static void main(String[] args) { Collection<Order> orders = new ArrayList<>(); orders.add(new Order(1,1)); orders.add(new Order(2,2)); orders.add(new Order(3,3)); orders.add(new Order(4,4)); orders.add(new Order(1,2)); orders.add(new Order(2,5)); orders = mergeOrders(orders); orders.forEach(order -> System.out.println("Order -> price: "+order.getPrice()+"; volume: "+order.getVolume())); }
Result:
Order -> price: 1; volume: 3
Order -> price: 2; volume: 7
Order -> price: 3; volume: 3
Order -> price: 4; volume: 4