[英]extract uncommon elements from list based on attribute in another list
我的結構
A {
String id;
String bid;
}
B {
String id;
}
特定
List<A> aList = Arrays.asList(
new A (1,2),
new A (2,5),
new A (3,9),
new A (4,10),
new A (5, 20),
new A (6, 8),
new A (7, 90)
new A (8, 1)
);
List<B> bList = Arrays.asList(
new B (2),
new B (9),
new B (10)
);
現在,我希望將與任何B元素都不匹配的A元素收集到另一個集合中,並且應該從A集合本身中刪除這些元素。
結果
List<A> aList = Arrays.asList(
new A (1,2),
new A (3,9),
new A (4,10)
);
List<A> aListBin = Arrays.asList(
new A (2,5),
new A (5, 20),
new A (6, 8),
new A (7, 90)
new A (8, 1)
);
我拿
我可以想到使用迭代器來迭代A,並針對A中的每個元素遍歷B,如果找到,則繼續添加其他內容,並使用迭代器remove刪除。
有使用流魔術的更好方法嗎? 謝謝
Collectors#partitionBy是您的朋友。
首先,我們將從B
的列表中提取id
到裸露的Set<Integer>
,因此我們可以將其用於查找:
Set<Integer> bSet = bList.stream()
.map(b -> b.id)
.collect(Collectors.toSet());
正如JB Nizet提到的那樣, HashSet
適合該工作。
然后就這么簡單–我們將按給定的謂詞進行分區。 謂詞是A.bid
是否包含在任何B.id
(為方便起見,我們將其存儲在bSet
中)。
Map<Boolean, List<A>> map = aList.stream()
.collect(Collectors.partitioningBy(a -> bSet.contains(a.bid)));
現在map.get(true)
包含B
包含的所有項目, map.get(false)
所有其他項目。
為了替換aList
,只需重新分配aList
:
aList = map.get(true);
您不能從使用Arrays.asList()創建的列表中刪除元素。 它返回您作為參數傳遞的數組的視圖,因此調用remove將引發UnsupportedOperationException。
假設您有ArrayList,我仍然認為您不能一步一步實現,當然也不能用“流魔術”來實現,因為流不允許您修改原始集合。
分兩個步驟:
List<A> newList = aList.stream()
.filter(a -> !bList.contains(a.bid))
.collect(Collectors.toList());
aList.removeAll(newList);
如果性能是一個問題,請使用Set或Map(以id為鍵)而不是List來分別在O(1)和O(n)中執行contains()和removeAll()。
是的,您可以使用Java 8 Streams 。
這是您輸入中的完整示例:
import java.util.*;
import java.util.stream.*;
import static java.util.stream.Collectors.toList;
public class MyClass {
public static void main(String args[]) {
class A {
public int id;
public int bid;
public A(int id, int bid) { this.id = id; this.bid = bid; }
public String toString() { return "(" + id + "," + bid + ")"; }
};
class B {
public int id;
public B(int id) { this.id = id; }
public String toString() { return "" + id; }
};
List<A> aList = Arrays.asList(
new A (1,2), // not removed
new A (2,5), // removed
new A (3,9), // not removed
new A (4,10), // not removed
new A (5, 20),// not removed
new A (6, 8), // not removed
new A (7, 90),// not removed
new A (8, 1)// not removed
);
List<B> bList = Arrays.asList(
new B (2),
new B (9),
new B (10)
);
List<A> aListBin = new ArrayList<>();
aList.stream()
.forEach( a -> {
if (bList.stream().noneMatch(b -> b.id == a.bid )) {
aListBin.add(a);
}
});
aList = aList.stream()
.filter( a -> bList.stream().anyMatch(b -> b.id == a.bid))
.collect(toList());
System.out.println("Alist-> " + aList);
System.out.println("Blist-> " + bList);
System.out.println("Removed-> " + aListBin);
}
}
輸出:
Alist-> [(1,2), (3,9), (4,10)]
Blist-> [2, 9, 10]
Removed-> [(2,5), (5,20), (6,8), (7,90), (8,1)]
您可以使用Collectors.partitioningBy
。 好點嗎? 取決於您的定義更好。 它是更簡潔的代碼,但是效率不如您描述的簡單迭代器循環。
除了可能使用字符串哈希集查找B類ID之外,我沒有想到一種比迭代器路由更有效的方法。
但是,如果您希望使用簡潔的代碼,則下面是使用partitioningBy的代碼:
class A {
int id;
int bid;
public A(int id, int bid){
this.id = id;
this.bid = bid;
}
public boolean containsBId(List<B> bList) {
return bList.stream().anyMatch(b -> bid == b.id);
}
}
class B {
int id;
public B(int id){
this.id = id;
}
}
class Main {
public static void main(String[] args) {
List<A> aList = Arrays.asList(
new A (1,2),
new A (2,5),
new A (3,9),
new A (4,10),
new A (5, 20),
new A (6, 8),
new A (7, 90),
new A (8, 1)
);
List<B> bList = Arrays.asList(
new B (2),
new B (9),
new B (10)
);
Map<Boolean, List<A>> split = aList.stream()
.collect(Collectors.partitioningBy(a -> a.containsBId(bList)));
aList = split.get(true);
List<A> aListBin = split.get(false);
}
由於您要處理兩個不同的類,因此無法直接比較它們。 因此,您需要簡化為最小公分母,即整數ID。
// start a stream of aList.
List<A> aListBin = aList.stream()
// Convert the bList to a collection of
// of ID's so you can filter.
.filter(a -> !bList.stream()
// get the b ID
.map(b->b.id)
// put it in a list
.collect(Collectors.toList())
// test to see if that list of b's ID's
// contains a's bID
.contains(a.bid))
//if id doesn't contain it, then at to the list.
.collect(Collectors.toList());
To finish up, remove the newly created list from the aList.
aList.removeAll(aListBin);
它們顯示如下:
System.out.println("aListBin = " + aListBin);
System.out.println("aList = " + aList);
aListBin = [[2, 5], [5, 20], [6, 8], [7, 90], [8, 1]]
aList = [[1, 2], [3, 9], [4, 10]]
注意:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.