如何在Java中检查Set是否包含某个字符串值的对象?

29

我有一组对象。每个对象都有一个字符串值。

我需要选择所有具有值等于“direction”的this 的对象。

是否可以在不迭代整个集合的情况下实现?


很遗憾,您将不得不遍历所有值。 - gefei
在Java 8中,这个变得容易了。 - mtyson
6个回答

31

一般而言,不行。您需要遍历集合并检查每个对象,以查看属性是否等于您搜索的值。这是一个 O(n) 操作。

有一种情况可以在不迭代的情况下完成。如果您的对象的 equals 方法是根据该 String 属性的相等性定义的,并且如果 hashCode 方法也正确实现,则可以使用 hashSet.contains 找到具有正确值的对象,而无需遍历整个集合,时间复杂度为 O(1)

正如我所提到的,这是一个非常特定的用例,而不是通用解决方案。如果字符串是某种唯一标识符,那么它可能有用,但不适用于您的特定用例。

您还可以考虑其他更适合您用例的集合。例如,如果您正在使用 Guava,则可以考虑使用 Multimap

相关


1
由于user710818提到了“所有对象”,我猜想字符串的值在集合中并不唯一。如果这样,改变等式会导致一个不良的副作用:当添加一个新对象时,具有相同字符串值的对象将被移除。 - Janoz

11
是的,这是通过覆盖 equals() 方法来实现的。
@Override 
public boolean  equals (Object object) {
     
}

你只是想检查equals方法是否正常工作。

代码:

package com.webapp.test;

import java.util.ArrayList;
import java.util.List;

public class EmployeeModel {    

    public EmployeeModel(String name, String designation, long age) {
        this.name = name;
        this.designation = designation;
        this.age = age;
    }

    private String name;
    private String designation;
    private long age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getDesignation() {
        return designation;
    }

    public void setDesignation(String designation) {
        this.designation = designation;
    }

    public long getAge() {
        return age;
    }

    public void setAge(long age) {
        this.age = age;
    }

    @Override
    public boolean equals (Object object) {
        boolean result = false;
        if (object == null || object.getClass() != getClass()) {
            result = false;
        } else {
            EmployeeModel employee = (EmployeeModel) object;
            if (this.name == employee.getName() && this.designation == employee.getDesignation() && this.age.equals(employee.getAge())) {
                result = true;
            }
        }
        return result;
    }
}

public static void main(String args[]) {
    EmployeeModel first = new EmployeeModel("Sameer", "Developer", 25);
    EmployeeModel second = new EmployeeModel("Jon", "Manager", 30);
    EmployeeModel third = new EmployeeModel("Priyanka", "Tester", 24);

    List<EmployeeModel> employeeList = new ArrayList<EmployeeModel>();
    employeeList.add(first);
    employeeList.add(second);
    employeeList.add(third);
    
    EmployeeModel checkUserOne = new EmployeeModel("Sameer", "Developer", 25);
    System.out.println("Check checkUserOne is in list or not ");
    System.out.println("Is checkUserOne Present = ? " + employeeList.contains(checkUserOne));
    
    EmployeeModel checkUserTwo = new EmployeeModel("Tim", "Tester", 24);
    System.out.println("Check checkUserTwo is in list or not");
    System.out.println("Is checkUserTwo Present = ? " + employeeList.contains(checkUserTwo));

}

输出:

Check checkUserOne is in list or not 
Is checkUserOne Present = ? true
Check checkUserTwo is in list or not 
Is checkUserTwo Present = ? false

必须注意,正如@MarkByers所提到的那样,除非它实际上实现了相等的功能,否则不应该覆盖equals()。问题说明字符串在多个示例中被使用,并且需要返回所有这些示例。因此,contains()equals()并不是好的选择。 - Felipe Leão

7

我知道这是一个老问题,但...

简短回答:不可能...

使用 equals()contains() 如其他人建议的应该仅限于您要过滤的属性实际上是对象身份的一部分的情况。我没有看到任何方法可行,只能使用 O(n) 算法。

如果您正在考虑本机函数,Java 8 带来了 Stream API函数式编程 的概念,允许更轻松、更清洁的循环调用。尽管如此,值得注意的是,在您的情况下,集合中的所有对象都必须进行检查,因此复杂度仍然为 O(n)。

Java 8 的 stream().filter() 示例

public static void main(String[] args...){
    Set<MyClass> mySet = new HashSet<>();
    mySet.add(new MyClass("Obj 1", "Rio de Janeiro"));
    mySet.add(new MyClass("Obj 2", "London"));
    mySet.add(new MyClass("Obj 3", "New York"));
    mySet.add(new MyClass("Obj 4", "Rio de Janeiro"));

    Set<MyClass> filtered = mySet.stream()
                                 .filter(mc -> mc.getCity().equals('Rio de Janeiro'))
                                 .collect(Collectors.toSet());

    filtered.forEach(mc -> System.out.println("Object: "+mc.getName()));

    // Result:
    //    Object: Obj 1 
    //    Object: Obj 4 
}

4

2
你仍然可以使用contains()方法。你只需要遍历初始的Set,并将其转换为只包含你想要检查是否存在于对象的Set中的字段值的字符串集合。请参考以下示例,该示例基于Felipe LeãoMichael Laffargue之前的答案。
public static void main(String[] args...){
     Set<MyClass> mySet = new HashSet<>();
     mySet.add(new MyClass("Obj 1"));
     mySet.add(new MyClass("Obj 2"));
     mySet.add(new MyClass("Obj 3"));

     Set<String> mapped = mySet.stream()
                             .map(MyClass::getField())
                             .collect(Collectors.toSet());

     mapped.contains("Obj 1");
     mapped.contains("Obj 2");
     mapped.contains("Obj 4");

     // Result:
     //     true 
     //     true
     //     false

}


1
我通过使用流API解决了这个问题:

Student ousama = students.stream()
  .filter(student -> "ousama".equals(student.getName()))
  .findAny()
  .orElse(null);

if(ousama != null) {
  //Exist
} else {
  //Doesn't exist
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接