Java 如何在计算两个列表之间的重复值时短路?

Java 如何在计算两个列表之间的重复值时短路?,java,list,java-8,java-stream,Java,List,Java 8,Java Stream,我有两个列表,我需要最快的方法来计数/检查列表A中与列表B中的元素匹配的重复元素 例如,如果列表A是[“A”,“B”,“C”],而列表B是[“X”,“B”,“B”,“A”,“C”,“C”],我的计数器应该是2,因为在B中有两个重复的元素(“B”和“C”)。因为它是一个布尔方法,每当重复出现B中的A时,它都应该返回true 我正在避免级联循环,甚至尝试使用流。虽然下面的代码可以工作,但我仍然不能确定它的设计。 我现在就是这样做的: class MyPojo { int value; Str

我有两个列表,我需要最快的方法来计数/检查列表A中与列表B中的元素匹配的重复元素

例如,如果列表A是
[“A”,“B”,“C”]
,而列表B是
[“X”,“B”,“B”,“A”,“C”,“C”]
,我的计数器应该是2,因为在B中有两个重复的元素
(“B”和“C”)
。因为它是一个布尔方法,每当重复出现B中的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;
}
类MyPojo{
int值;字符串str;
MyPojo(int-value){this.value=value;};
/*获取者和设置者*/
}
公共静态布尔值hasDuplicates(){
listForbiddenValues=Arrays.asList(1,2,3);
List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2),
新MyPojo(2)、新MyPojo(3)、新MyPojo(3)、新MyPojo(4));
for(整数值:禁止值){
long count=pojoList.stream()
.filter(pojoElement->pojoElement.getValue()==value)
.count();
//如果单个迭代中的计数大于1,则返回true
如果(计数>1){
返回true;
}
}
返回false;
}
这将起作用

    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();
    }
}
public静态布尔hasdeplicates(){
listForbiddenValues=Arrays.asList(新的MyPojo(1),新的MyPojo(2),
新MyPojo(3));
List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2),
新MyPojo(2)、新MyPojo(3)、新MyPojo(3)、新MyPojo(4));
for(MyPojo i:禁止值){
if(pojoList.contains(i))
返回true;
}
返回false;
}
}
MyPojo类{
int值;字符串str;
MyPojo(int-value){this.value=value;};
public int getValue(){
返回此.value;
}
@凌驾
公共布尔等于(对象o){
如果(o==这个)
返回true;
如果(!(MyPojo的o实例))
返回false;
MyPojo p=(MyPojo)o;
返回此.value==p.getValue();
}
}

这对您很有用。让我知道你有任何问题。如果需要,也可以使用并行流

使用流API

public静态布尔hasdeplicates(){
listForbiddenValues=Arrays.asList(1,2,3);
List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2),
新MyPojo(2)、新MyPojo(3)、新MyPojo(3)、新MyPojo(4));
long count=pojoList.stream()
.filter(pojo->forbiddenValues.contains(pojo.getValue()))
.map(MyPojo::getValue)
.collect(收集器.groupingBy(值->值))
.values()
.stream()
.filter(值->值.size()>1)
.count();
返回计数>1;
}
没有流

public静态布尔hasdeplicates(){
listForbiddenValues=Arrays.asList(1,2,3);
List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2),
新MyPojo(2)、新MyPojo(3)、新MyPojo(3)、新MyPojo(4));
映射计数=新的HashMap();
for(整数禁止:禁止值){
计数。放置(禁止,0);
}
for(MyPojo MyPojo:pojoList){
if(counts.containsKey(myPojo.getValue())){
int count=counts.get(myPojo.getValue());
如果(计数=1){
返回true;
}
counts.put(myPojo.getValue(),count+1);
}
}
返回false;
}

我建议使用纯命令式循环而不是流,因为后者往往会导致比您想象的更多的开销

所以,在这种情况下,我会先从嵌套for each循环开始,然后再考虑流

此外,如果您决定继续使用流方法,您可以做的一个改进是在
计数之前调用
limit(2)
,以便尽可能短路。

公共静态布尔hasdeplicates(){
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;
}
listForbiddenValues=Arrays.asList(1,2,3); List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2), 新MyPojo(2)、新MyPojo(3)、新MyPojo(3), 新MyPojo(4)); 地图= pojoList.stream().collect(收集器.groupingBy(MyPojo::getValue), 收集器。计数(); 布尔结果= 禁止值.stream().filter(map::containsKey).map(map::get) .anyMatch(计数->计数>1); 返回结果; }
使用
HashSet
检查元素是否存在,因为
包含的
要快得多,按照@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;
    }
public静态布尔hasdeplicates(){
listForbiddenValues=Arrays.asList(1,2,3);
设置禁止值Set=新哈希集(禁止值);
List-pojoList=Arrays.asList(新的MyPojo(0),新的MyPojo(2),
新MyPojo(2)、新MyPojo(3)、新MyPojo(3)、新MyPojo(4));
long count=pojoList.stream()
.filter(t->禁止值set.contains(t.value)).limit(2.count();
返回计数>1;
}
您可以使用

return pojoList.stream()
        .map(MyPojo::getValue)
        .filter(forbiddenValues::contains)
        .collect(Collectors.toMap(Function.identity(), value -> false, (a, b) -> true))
        .containsValue(true);
  • 首先,将
    MyPojo
    元素映射到值
  • 然后只让那些包含在
    禁止值中的值通过(为了提高效率,强烈建议在集合变得更大时使用
    集合)
  • 使用值作为键收集到映射,并最初映射到
    false
    ,但使用合并函数,如果出现重复键,该函数将计算为
    true
  • 如果生成的映射包含任何
    true
    值,则我们有duplica
    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;
        }
    
    return pojoList.stream()
            .map(MyPojo::getValue)
            .filter(forbiddenValues::contains)
            .collect(Collectors.toMap(Function.identity(), value -> false, (a, b) -> true))
            .containsValue(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;