我有2个列表,我需要以最快的方式计算/检查列表A中与列表B中的元素匹配的重复元素。
例如,如果列表A是["A", "B", "C"]
而列表B是["X", "B", "B", "A", "C", "C", "C"]
,那么我的计数器应该是2,因为B中有2个重复的元素("B" & "C")
。因为它是一个布尔方法,只要重复出现A中的A,它就应该返回true。
我正在避免级联循环甚至尝试使用流。虽然以下代码有效,但我对它的设计仍然不太确定。 这就是我现在正在做的事情:
class MyPojo {
int value; String str;
MyPojo(int value) { this.value = value; };
/* getters & setters*/
}
public static boolean hasDuplicates() {
List<Integer> forbiddenValues = Arrays.asList(1, 2, 3);
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3), new MyPojo(4));
for ( Integer value : forbiddenValues) {
long count = pojoList.stream()
.filter( pojoElement -> pojoElement.getValue() == value)
.count();
// returns true if in a single iteration count is greater than 1
if ( count > 1) {
return true;
}
}
return false;
}
答案 0 :(得分:2)
这对你有用。让我知道你有任何问题。如果需要,您也可以使用并行流。
使用Stream API
public static boolean hasDuplicates() {
List<Integer> forbiddenValues = Arrays.asList(1, 2, 3);
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3), new MyPojo(4));
long count = pojoList.stream()
.filter(pojo -> forbiddenValues.contains(pojo.getValue()))
.map(MyPojo::getValue)
.collect(Collectors.groupingBy(value -> value))
.values()
.stream()
.filter(values -> values.size() > 1)
.count();
return count > 1;
}
无流
public static boolean hasDuplicates() {
List<Integer> forbiddenValues = Arrays.asList(1, 2, 3);
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3), new MyPojo(4));
Map<Integer, Integer> counts = new HashMap<>();
for(int forbidden : forbiddenValues){
counts.put(forbidden, 0);
}
for(MyPojo myPojo : pojoList){
if(counts.containsKey(myPojo.getValue())){
int count = counts.get(myPojo.getValue());
if(count == 1){
return true;
}
counts.put(myPojo.getValue(), count + 1);
}
}
return false;
}
答案 1 :(得分:2)
使用HashSet
检查元素是否存在,因为contains
要快得多,并且按照@Aonimé建议你可以这样做。
public static boolean hasDuplicates() {
List<Integer> forbiddenValues = Arrays.asList(1, 2, 3);
Set<Integer> forbiddenValuesSet = new HashSet<>(forbiddenValues);
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3), new MyPojo(4));
long count = pojoList.stream()
.filter(t -> forbiddenValuesSet.contains(t.value)).limit(2).count();
return count > 1;
}
答案 2 :(得分:2)
您可以使用
return pojoList.stream()
.map(MyPojo::getValue)
.filter(forbiddenValues::contains)
.collect(Collectors.toMap(Function.identity(), value -> false, (a, b) -> true))
.containsValue(true);
MyPojo
元素映射到值forbiddenValues
中包含的那些传递(为了提高效率,强烈建议在集合变大时使用Set
)false
,但使用 merge 函数,对于任何重复键的出现,它将评估为true
< / LI>
true
值,则我们有重复的密钥这与其他已发布的答案类似,但会跳过许多不必要的操作。但是,它需要在我们查询副本之前构建整个映射,因此,循环可能仍然更快:
Set<Integer> seen = new HashSet<>();
for(MyPojo pojo: pojoList) {
Integer value = pojo.getValue();
if(forbiddenValues.contains(value) && !seen.add(value)) return true;
}
return false;
Set.add
返回是否将值添加到集合中,即它是否已包含在集合中。因此,只要此方法返回false
,我们就知道遇到了重复。
答案 3 :(得分:1)
我建议使用纯粹的命令式循环而不是流,因为后者往往会导致比你想象的更多的开销。
所以,在这种情况下,我会先考虑每个循环嵌套,然后再考虑Streams。
此外,如果您决定继续使用流方法,那么您可以做的一项改进是在limit(2)
急切操作之前调用count
以尽可能短路。
答案 4 :(得分:0)
public static boolean hasDuplicates() {
List<Integer> forbiddenValues = Arrays.asList(1, 2, 3);
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3),
new MyPojo(4));
Map<Integer, Long> map =
pojoList.stream().collect(Collectors.groupingBy(MyPojo::getValue,
Collectors.counting()));
boolean result =
forbiddenValues.stream().filter(map::containsKey).map(map::get)
.anyMatch(count -> count > 1);
return result;
}
答案 5 :(得分:-1)
这样可行。
public static boolean hasDuplicates() {
List<MyPojo> forbiddenValues = Arrays.asList(new MyPojo(1), new MyPojo(2),
new MyPojo(3));
List<MyPojo> pojoList = Arrays.asList(new MyPojo(0), new MyPojo(2),
new MyPojo(2), new MyPojo(3), new MyPojo(3), new MyPojo(4));
for(MyPojo i : forbiddenValues){
if(pojoList.contains(i))
return true;
}
return false;
}
}
class MyPojo {
int value; String str;
MyPojo(int value) { this.value = value; };
public int getValue(){
return this.value;
}
@Override
public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof MyPojo))
return false;
MyPojo p = (MyPojo) o;
return this.value==p.getValue();
}
}