首页 > 解决方案 > 按对象类型的字段值搜索重复项在列表中

问题描述

我不确定我的问题是否清楚,但我试图在列表中查找重复的对象,如果它们在具有相同值的对象中有 1 个或多个字段,则它们是重复的。我还试图使其对许多数据类具有通用性和可重用性。

这是我刚刚提出的解决方案。如果发现重复,则返回 true,否则返回 false。这个解决方案好吗?或者还有什么我可以用来实现我的目标的吗?

(编辑为忽略空值)

public class TestObject {
    private String str;

    public TestObject(String str){
      this.str = str;
    }
}

public static <T> boolean checkForDuplicateByFields(List<T> ls, String... fieldNames) {
    if (ls == null || ls.isEmpty()) {
      return false;
    }

    //create hashset of <fieldName, values>
    HashMap<String, HashSet<Object>> map = new HashMap<>();
    for (String name : fieldNames) {
      map.put(name, new HashSet<>());
    }

    // Search for duplicates of fields' value in list <T>
    for (String name : fieldNames) {
      try {
        Field f = ls.get(0).getClass().getDeclaredField(name);
        f.setAccessible(true);
        for (T obj : ls) {
          try {
            HashSet<Object> names = map.get(name);
            Object o = f.get(obj);
            if(o == null){
              continue;
            }
            if (names.isEmpty()) {
              names.add(o);
            } else if (names.contains(o)) {
              return true;
            }
          } catch (IllegalAccessException ex) {
            break;
          }
        }
      } catch (NoSuchFieldException ex) {
        break;
      }
    }
    return false;
}

public static void main(String[] args){
    List<TestObject> ls = new ArrayList<>();
    TestObject obj = new TestObject("hello");
    ls.add(obj);
    ls.add(obj);
    System.out.println(checkForDuplicateByFields(ls, "str"));

}

标签: java

解决方案


考虑到每个字段都有 getter 方法,我认为您可以使用 lambda 和功能接口以更简洁的方式完成此操作。
考虑以下示例:

public class App 
{
    public static void main( String[] args )
    {
         Student s = new Student(100,"xyz");
         Function<Student,Integer> studentRNMapper = ((student) -> student.getRollNumber());
         System.out.println(studentRNMapper.apply(s)); // print 100

         Function<Student,String> studentNameMapper = ((student) -> student.getName());
         System.out.println(studentNameMapper.apply(s)); // print "xyz"
    }
}

class Student {

    private Integer rollNumber;
    private String name;
    public Student(Integer rollNumber,String name) {
        this.rollNumber = rollNumber;
        this.name = name;
    }

    public Integer getRollNumber() {
        return rollNumber;
    }

    public String getName() {
        return this.name;
    }

}

您可以考虑传递功能接口,而不是传递字段名称。这样您就不必使用反射 API。在你的情况下,它看起来像这样:

TestObject obj = new TestObject("hello");
ls.add(obj);
ls.add(obj);
Function<TestObject,String> testStrMapper = ((TestObject) -> TestObject.getStr());
System.out.println(checkForDuplicateByFields(ls, testStrMapper);

在您的 checkForDuplicateByFields 中,您将检索如下值:

testStrMapper.supply(ls.get(i)) <-- Return value of str field for the ith object.

推荐阅读