Как удалить дубликаты элементов из arrayList, но суммировать их параметры? - PullRequest
2 голосов
/ 06 ноября 2019

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

Item name Apples, code 5649.0, quantity 1, exp date 2019-07-03.

Item name Oranges, code 124123.0, quantity 3, exp date 2019-12-04.

Item name Oranges, code 124123.0, quantity 4, exp date 2019-12-04.

Item name Peach, code 946598.0, quantity 1, exp date 2017-11-10.

Item name Tomatoes, code 6.5987989764689741E17, quantity 2, exp date 2019-06-20.

Объект имеет эти атрибуты

 private String name;

 private double code;

 private int quantity;

 private String expDate;

Теперь мне нужно удалить дубликаты, но суммировать количество, если имя, дата опыта и код совпадают (например, чтобы оставить одну строкус апельсинами, но меняю количество до 7).

Я думаю о чем-то подобном, но понятия не имею, что писать в цикле.


for(Item a : itemsNeed) {
            for(int b=1; b<itemsNeed.size(); b++) {
                if(a.getCode()==itemsNeed.get(b).getCode() && a.getExpDate().equals(itemsNeed.get(b).getExpDate())) {


                }
            }

Это то, о чем я думаю, ноне знаю куда двигаться дальше. Это правильно? Или есть другое, более простое решение?

Ответы [ 2 ]

0 голосов
/ 06 ноября 2019

Еще раз подход с использованием функции groupingBy потоков, без ломбоков и некоторых стилевых различий.

Отображение может выглядеть следующим образом

    List<Item> items = new ArrayList<>();
    Map<ItemGroupKey, Integer> grouped = items.stream()
            .collect(Collectors.groupingBy(ItemGroupKey::new, summingInt(Item::getQuantity)));
    List<Item> dedupedSummed = grouped.entrySet().stream()
            .map(t -> t.getKey().getItem().forQuantity(t.getValue()))
            .collect(Collectors.toList());

, но вам нужно настроитьпрежде чем он сможет работать, это механизм, где ItemGroupKey указывает на два элемента как равные, когда их имя, код и expirationDate равны. Обратите внимание, что вам нужно добавить соответствующую реализацию hashCode(). Я решил использовать метод Item.forQuantity для создания копии товара с заданным количеством.

   class ItemGroupKey{
    private final Item item;

    ItemGroupKey(Item item) {
        this.item = item;
    }

    public Item getItem() {
        return item;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        ItemGroupKey other = (ItemGroupKey) o;
        return Double.compare(other.getItem().getCode(), item.getCode()) == 0 &&
                Objects.equals(other.getItem().getName(), item.getName()) &&
                Objects.equals(other.getItem().getExpDate(), item.getExpDate());
    }

    @Override
    public int hashCode() {
        return Objects.hash(item.getCode(), item.getName(), item.getExpDate());
    }
}

class Item {
    private final String name;
    private final double code;
    private final int quantity;
    private final String expDate;

    Item(String name, double code, int quantity, String expDate) {
        this.name = name;
        this.code = code;
        this.quantity = quantity;
        this.expDate = expDate;
    }

    public Item forQuantity(int quantity){
        return new Item(name, code, quantity, expDate);
    }

    public String getName() {
        return name;
    }

    public double getCode() {
        return code;
    }

    public int getQuantity() {
        return quantity;
    }

    public String getExpDate() {
        return expDate;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        Item item = (Item) o;
        return Double.compare(item.code, code) == 0 &&
                quantity == item.quantity &&
                Objects.equals(name, item.name) &&
                Objects.equals(expDate, item.expDate);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name, code, quantity, expDate);
    }
}
0 голосов
/ 06 ноября 2019

Используйте правильную составную структуру ключа и создайте функцию отображения - затем предоставьте ее потоковому сборщику groupingBy с summingInt нисходящим потоком и создайте заново список Item объектов на основе собранных данных

Iбудет использовать Lombok, чтобы представить пример ниже, но в основном я имею в виду создание неизменяемого ItemKey класса с правильными HashCode / Equals реализациями и добавление конструктора в Item классе для воссоздания Item объекта из ItemKey ирассчитанная величина (это может быть реализовано другим способом, например, с использованием некоторого заводского метода)

@Data
@AllArgsConstructor
class Item {
    private String name;

    private double code;

    private int quantity;

    private String expDate;

    public Item(ItemKey key, int quantity) {
        this.name = key.getName();
        this.code = key.getCode();
        this.expDate = key.getExpDate();
        this.quantity = quantity;
    }
}

@Value
class ItemKey {
    private String name;
    private double code;
    private String expDate;
}

// ... 

Function<Item, ItemKey> compositeKey = item -> new ItemKey(item.getName(), item.getCode(), item.getExpDate());

List<Item> filteredAndQuantityAggregated = itemsNeed.stream()
    .collect(Collectors.groupingBy(compositeKey, Collectors.summingInt(Item::getQuantity)))
    .entrySet()
    .stream()
    .map(entry -> new Item(entry.getKey(), entry.getValue()))
    .collect(Collectors.toList());
...