[英]Java Arraylist<Object> want to merge the objects if they have the same property value
Java ArrayList
,填充有稱為packinglistrows的對象,該對象包含三個鍵值(ISBN,PalletNumber,Quantity)以及其他屬性。
我有所有相同的ISBN值的ArrayList
。 我希望能夠合並具有相同PalletNumbers數量值的項目。
例如:
ArrayList items = [ packinglistrow( 1234, 1, 10 ), packinglistrow( 1234, 2, 5), packinglistrow( 1234, 1, 15 ) ]
合並后,[0]和[2]對象將合並,因為它們具有相同的ISBN和托盤編號1。結果是合並后的對象具有更新的數量:
ArrayList items = [ packinglistrow( 1234, 1, 25 ), packinglistrow( 1234, 2, 5) ]
是否正在考慮循環並比較不同類型並將其添加到新的ArrayList
然后循環並合並,但是這樣做必須有一種更整潔的方法嗎?
謝謝。
首先創建一個類來處理這些數據。 有兩點需要注意。 equals和hashcode方法僅基於isbn
和palletNumber
值,並且存在一種merge
方法,該方法返回PackingListRow
的新實例, PackingListRow
帶有該實例與您作為參數給出的另一個實例之間的數量。
class PackingListRow {
private final String isbn;
private final int palletNumber;
private final int quantity;
public PackingListRow(String isbn, int palletNumber, int quantity) {
this.isbn = isbn;
this.palletNumber = palletNumber;
this.quantity = quantity;
}
public String getIsbn() {
return isbn;
}
public int getPalletNumber() {
return palletNumber;
}
public int getQuantity() {
return quantity;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PackingListRow that = (PackingListRow) o;
return Objects.equals(palletNumber, that.palletNumber) &&
Objects.equals(isbn, that.isbn);
}
@Override
public int hashCode() {
return Objects.hash(isbn, palletNumber);
}
@Override
public String toString() {
return "PackingListRow{" +
"isbn='" + isbn + '\'' +
", palletNumber=" + palletNumber +
", quantity=" + quantity +
'}';
}
public PackingListRow merge(PackingListRow other) {
assert(this.equals(other));
return new PackingListRow(this.isbn, this.palletNumber, this.quantity + other.quantity);
}
}
一旦有了它,您只需要創建另一個新列表,該列表最初是空的。 它將包含合並的值。 對於初始列表中的每個實例,請檢查它是否已在合並列表中。 如果是,則通過調用merge修改現有實例,否則只需將其附加到列表中即可。 我們最終得到以下算法:
List<PackingListRow> list =
Arrays.asList(new PackingListRow("1234", 1, 10), new PackingListRow("1234", 2, 5), new PackingListRow("1234", 1, 15));
List<PackingListRow> mergedList = new ArrayList<>();
for(PackingListRow p : list) {
int index = mergedList.indexOf(p);
if(index != -1) {
mergedList.set(index, mergedList.get(index).merge(p));
} else {
mergedList.add(p);
}
}
System.out.println(mergedList);
哪個輸出:
[PackingListRow{isbn='1234', palletNumber=1, quantity=25}, PackingListRow{isbn='1234', palletNumber=2, quantity=5}]
對於Java 8,我可能會使用不同的策略(至少您展示了解決問題的多種方法)。 我將創建一個靜態類為我做分組:
class PackingListRow {
private final String isbn;
private final int palletNumber;
private final int quantity;
static class GroupPacking {
private final String isbn;
private final int palletNumber;
public GroupPacking(PackingListRow p) {
this.isbn = p.isbn;
this.palletNumber = p.palletNumber;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
GroupPacking that = (GroupPacking) o;
return Objects.equals(palletNumber, that.palletNumber) &&
Objects.equals(isbn, that.isbn);
}
@Override
public int hashCode() {
return Objects.hash(isbn, palletNumber);
}
}
....
public PackingListRow merge(PackingListRow other) {
assert (new GroupPacking(other).equals(new GroupPacking(this)));
return new PackingListRow(this.isbn, this.palletNumber, this.quantity + other.quantity);
}
}
然后,您可以使用Stream API。 給定原始列表,您將獲得Stream<PackingListRow>
,然后根據它們的GroupPacking實例(鍵)將元素收集到Map中。 該值只是當前的PackingListRow
實例。 如果您有兩個實例具有相同的GroupPacking值(根據equals / hashcode),則將它們合並。 您最終獲得了地圖的values()
。
List<PackingListRow> mergedList =
new ArrayList<>(list.stream().collect(toMap(PackingListRow.GroupPacking::new, p -> p, PackingListRow::merge)).values());
這里有一個工作示例(Java8 + Google Guava):
package com.rgrebski.test;
import com.google.common.base.*;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Multimaps;
import org.assertj.core.api.Assertions;
import org.testng.annotations.*;
import java.util.Collection;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;
public class PackingListRowMergeTest {
@Test
public void test() {
//given
List<PackingListRow> packingListRow = ImmutableList.of(
new PackingListRow(1234, 1, 10),
new PackingListRow(1234, 2, 5),
new PackingListRow(1234, 1, 15)
);
//when
List<PackingListRow> mergedPackingListRow = Multimaps.index(packingListRow, groupByPaletNumbers())
.asMap()
.values()
.stream()
.map(packingListRowCollectionToSinglePackingListRowWithQuantitySum())
.collect(Collectors.toList());
//then
Assertions.assertThat(mergedPackingListRow).containsExactly(
new PackingListRow(1234, 1, 25),
new PackingListRow(1234, 2, 5)
);
}
protected java.util.function.Function<Collection<PackingListRow>, PackingListRow> packingListRowCollectionToSinglePackingListRowWithQuantitySum() {
return new java.util.function.Function<Collection<PackingListRow>, PackingListRow>() {
@Override
public PackingListRow apply(Collection<PackingListRow> packingListRows) {
int quantitySum = packingListRows.stream().flatMapToInt(packingListRow -> IntStream.of(packingListRow.getQuantity())).sum();
PackingListRow firstPackingListRow = packingListRows.stream().findFirst().get();
return new PackingListRow(firstPackingListRow.getIsbn(), firstPackingListRow.getPaletNumber(), quantitySum);
}
};
}
private Function<? super PackingListRow, Integer> groupByPaletNumbers() {
return new Function<PackingListRow, Integer>() {
@Override
public Integer apply(PackingListRow input) {
return input.getPaletNumber();
}
};
}
private static class PackingListRow {
private int isbn;
private int paletNumber;
private int quantity;
public PackingListRow(int isbn, int paletNumber, int quantity) {
this.isbn = isbn;
this.paletNumber = paletNumber;
this.quantity = quantity;
}
public int getIsbn() {
return isbn;
}
public int getPaletNumber() {
return paletNumber;
}
public int getQuantity() {
return quantity;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
PackingListRow that = (PackingListRow) o;
return Objects.equal(this.isbn, that.isbn) &&
Objects.equal(this.paletNumber, that.paletNumber) &&
Objects.equal(this.quantity, that.quantity);
}
@Override
public int hashCode() {
return Objects.hashCode(isbn, paletNumber, quantity);
}
@Override
public String toString() {
return MoreObjects.toStringHelper(this)
.add("isbn", isbn)
.add("paletNumber", paletNumber)
.add("quantity", quantity)
.toString();
}
}
}
為ISBN和貨盤號創建一個對象似乎是合理的,但是如果ISBN和貨盤號相等,則將數量分開,因為您認為它們相等。 因此對象可能看起來像這樣:
public class PackingListRow {
private final String isbn;
private final int palletNumber;
public PackingListRow(String isbn, int palletNumber) {
this.isbn = isbn;
this.palletNumber = palletNumber;
}
@Override
public int hashCode() {
return palletNumber * 31 + ((isbn == null) ? 0 : isbn.hashCode());
}
@Override
public boolean equals(Object obj) {
if (this == obj)
return true;
if (obj == null)
return false;
if (getClass() != obj.getClass())
return false;
PackingListRow other = (PackingListRow) obj;
if (isbn == null) {
if (other.isbn != null)
return false;
} else if (!isbn.equals(other.isbn))
return false;
if (palletNumber != other.palletNumber)
return false;
return true;
}
@Override
public String toString() {
return isbn+":"+palletNumber;
}
}
之后,您可以將結果存儲在Map
對象中,並通過如下方法添加項目:
public static void addItem(Map<PackingListRow, Integer> items, PackingListRow row,
int quantity) {
Integer oldQuantity = items.get(row);
items.put(row, oldQuantity == null ? quantity : quantity+oldQuantity);
}
如果您使用Java 8,則更為簡單:
public static void addItem(Map<PackingListRow, Integer> items, PackingListRow row,
int quantity) {
items.merge(row, quantity, Integer::sum);
}
測試樣本數據:
public static void main(String[] args) {
Map<PackingListRow, Integer> items = new HashMap<PackingListRow, Integer>();
addItem(items, new PackingListRow("1234", 1), 10);
addItem(items, new PackingListRow("1234", 2), 5);
addItem(items, new PackingListRow("1234", 1), 15);
System.out.println(items);
}
輸出為:
{1234:1=25, 1234:2=5}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.