Найти, если объекты в коллекции имеют одинаковые значения полей - PullRequest
0 голосов
/ 16 мая 2018

Я пытаюсь создать редактор для редактирования нескольких устройств, выбранных в JTree.

Если все элементы в Коллекции имеют одно и то же значение для определенного поля, я отобразлю это значение в форме редактора.Если они имеют разные значения, я буду отображать «Несколько значений»

Я пытался использовать что-то подобное, но это ограничивается сравнением двух элементов.Я хочу сделать это для всех предметов в коллекции.

 private static List<String> difference(Student s1, Student s2) {
 List<String> values = new ArrayList<>();
 for (Field field : s1.getClass().getDeclaredFields()) {
    // You might want to set modifier to public first (if it is not public yet)
    field.setAccessible(true);
    Object value1 = field.get(s1);
    Object value2 = field.get(s2); 
    if (value != null && value != null) {
        System.out.println(field.getName() + "=" + value1);
        System.out.println(field.getName() + "=" + value2);
        if (!Objects.equals(value1, value2) {
            values.add(value2);
        }
    }
}
return values;

}

Может ли кто-нибудь привести пример того, как вы определяете поля, которые имеют одинаковые значения для объектов в коллекции?

Мой код Hash and Equals указан ниже.Я предполагаю, что это может быть достигнуто с использованием встроенных методов Collection, но я был бы признателен за пример.

    @Override
public int hashCode() {
    int hash = 5;
    hash = 47 * hash + (this.isSelected ? 1 : 0);
    hash = 47 * hash + Objects.hashCode(this.user);
    hash = 47 * hash + Objects.hashCode(this.password);
    hash = 47 * hash + Objects.hashCode(this.address);
    hash = 47 * hash + (int) (this.addressAsLong ^ (this.addressAsLong >>> 32));
    hash = 47 * hash + this.port;
    hash = 47 * hash + Objects.hashCode(this.vendor);
    hash = 47 * hash + Objects.hashCode(this.model);
    hash = 47 * hash + Objects.hashCode(this.OS);
    hash = 47 * hash + Objects.hashCode(this.description);
    hash = 47 * hash + Objects.hashCode(this.version);
    hash = 47 * hash + Objects.hashCode(this.hostName);
    hash = 47 * hash + Objects.hashCode(this.domain);
    hash = 47 * hash + Objects.hashCode(this.deviceType);
    hash = 47 * hash + Objects.hashCode(this.Location);
    hash = 47 * hash + Objects.hashCode(this.SerialNumber);
    // hash = 47 * hash + Objects.hashCode(this.parent);
    return hash;
}

@Override
public boolean equals(Object obj) {
    if (this == obj) {
        return true;
    }
    if (obj == null) {
        return false;
    }
    if (getClass() != obj.getClass()) {
        return false;
    }
    final DefaultDevice other = (DefaultDevice) obj;
    if (this.isSelected != other.isSelected) {
        System.out.println("isSelected");
        return false;
    }
    if (this.addressAsLong != other.addressAsLong) {
        // System.out.println("long");
        return false;
    }
    if (this.port != other.port) {
        //System.out.println("port");
        return false;
    }
    if (!Objects.equals(this.user, other.user)) {
        // System.out.println("user");
        return false;
    }
    if (!Objects.equals(this.password, other.password)) {
        //System.out.println("pass");
        return false;
    }

    if (!Objects.equals(this.vendor, other.vendor)) {
        //System.out.println("ven");
        return false;
    }
    if (!Objects.equals(this.model, other.model)) {
        //System.out.println("mod");
        return false;
    }
    if (!Objects.equals(this.OS, other.OS)) {
        // System.out.println("os");
        return false;
    }
    if (!Objects.equals(this.description, other.description)) {
        //System.out.println("des");
        return false;
    }
    if (!Objects.equals(this.version, other.version)) {
        //System.out.println("ver");
        return false;
    }
    if (!Objects.equals(this.hostName, other.hostName)) {
        // System.out.println("hostNa");
        return false;
    }
    if (!Objects.equals(this.domain, other.domain)) {
        // System.out.println("dom");
        return false;
    }
    if (!Objects.equals(this.deviceType, other.deviceType)) {
        // System.out.println("dt");
        return false;
    }
    if (!Objects.equals(this.Location, other.Location)) {
        //System.out.println("loc");
        return false;
    }
    if (!Objects.equals(this.SerialNumber, other.SerialNumber)) {
        // System.out.println("sn");
        return false;
    }

    return true;
}

1 Ответ

0 голосов
/ 17 мая 2018

Комплексное решение, учитывающее доступность, использование методов получения / установки вместо доступа к полю и т. Д., Потребует немало усилий, но в рамках того, что вы описываете, алгоритм может выглядеть следующим образом:

  • в вашем методе возвращает объект типа, который вы повторяете в качестве результата, и принимайте его со значениями по умолчанию для случая несоответствия (замените их на Map<String, Object>, если хотите)
  • извлеките первый элементнепустого набора и определения его класса
  • итерация по всем объявленным полям, для каждого берется значение из первого элемента, а затем итерация по элементам до первого несовпадения
  • , если не совпадает, назначитьзначение по умолчанию и прерывание итерации
  • установить найденное значение в поле результата и перейти к следующему полю

В коде это выглядит так:

class ObjectMatcher {

    // NPE on null items
    // assumes public default constructor for T is available
    public <T> T match(Collection<T> items, T defaults) {
        if (items.isEmpty()) {
            return defaults;
        }
        try {
            @SuppressWarnings("unchecked")
            Class<T> clazz = (Class<T>) items.iterator().next().getClass();
            Field[] fields = clazz.getDeclaredFields();

            T res = clazz.newInstance();

            for (Field field : fields) {
                boolean firstItem = true;
                Object match = null;
                for (T item : items) {
                    Object value = field.get(item);
                    if (firstItem) {
                        match = value;
                    }
                    else if (!Objects.equals(value, match)) {
                        match = field.get(defaults);
                        break;
                    } // otherwise keep the match as is
                    firstItem = false;
                }
                field.set(res, match);
            }
            return res;
        }
        catch (IllegalAccessException | InstantiationException e) {
            throw new RuntimeException(e);
        }
    }
}

А вот простой тест для случая несоответствия поля, совпадения и нулевого / ненулевого несоответствия:

@Test
public void match_onMistmatchMatchAndNull_ok() {
    Student s1 = new Student("Andrew", "Physics", null);
    Student s2 = new Student("Joe", "Physics", 3.45);
    Student s3 = new Student("Nicki", "Physics", 2.39);

    Student defaults = new Student("Multiple Names", "Multiple Courses", 1.0);

    ObjectMatcher matcher = new ObjectMatcher();
    Student res = matcher.match(Arrays.asList(s1, s2, s3), defaults);

    assertEquals("Multiple Names", res.name);
    assertEquals("Physics", res.course);
    assertEquals(1.0, res.grade.doubleValue(), 0.001);
}

You wiВы найдете полный код для тестового класса в выделенном репозитории GitHub .

...