Java - отличительный список объектов

У меня есть список/коллекция объектов, которые могут иметь или не иметь одинаковые значения свойств. Какой самый простой способ получить отдельный список объектов с равными свойствами? Является ли один тип коллекции наиболее подходящим для этой цели? Например, в С# я мог бы сделать что-то вроде LINQ.

var recipients = (from recipient in recipientList
                 select recipient).Distinct();

Моя первоначальная мысль заключалась в том, чтобы использовать lambdaj (текст ссылки), но, похоже, это не поддерживает.

Ответ 1

Используйте реализацию интерфейса Set<T> (для класса T может потребоваться собственный метод .equals(), и вам, возможно, придется реализовать это .equals() самостоятельно). Обычно HashSet делает это из коробки: для сравнения объектов используется метод Object.hashCode() и Object.equals(). Это должно быть достаточно уникальным для простых объектов. Если нет, вам придется реализовать T.equals() и T.hashCode() соответственно.

См. комментарий Gaurav Saini ниже для библиотек, помогающих реализовать equals и hashcode.

Ответ 2

return new ArrayList(new HashSet(recipients));

Ответ 3

Поместите их в TreeSet, который содержит пользовательский Comparator, который проверяет необходимые свойства:

SortedSet<MyObject> set = new TreeSet<MyObject>(new Comparator<MyObject>(){

    public int compare(MyObject o1, MyObject o2) {
         // return 0 if objects are equal in terms of your properties
    }
});

set.addAll(myList); // eliminate duplicates

Ответ 5

Если вы используете Eclipse Collections, вы можете использовать метод distinct().

ListIterable<Integer> integers = Lists.mutable.with(1, 3, 1, 2, 2, 1);
Assert.assertEquals(
    Lists.mutable.with(1, 3, 2),
    integers.distinct());

Преимущество использования distinct() вместо преобразования в набор, а затем обратно в список состоит в том, что distinct() сохраняет порядок исходного списка, сохраняя первое вхождение каждого элемента. Он реализован с использованием как Set, так и List.

MutableSet<T> seenSoFar = Sets.mutable.with();
int size = list.size();
for (int i = 0; i < size; i++)
{
    T item = list.get(i);
    if (seenSoFar.add(item))
    {
        targetCollection.add(item);
    }
}
return targetCollection;

Если вы не можете преобразовать исходный список в тип коллекций Eclipse, вы можете использовать ListAdapter для получения того же API.

MutableList<Integer> distinct = ListAdapter.adapt(integers).distinct();

Примечание. Я являюсь коммиттером для коллекций Eclipse.

Ответ 6

порядок сохранения версии вышеупомянутого ответа

return new ArrayList(new LinkedHashSet(recipients));

Ответ 7

Вы можете использовать Set. Существует несколько вариантов реализации:

  • HashSet использует объект hashCode и equals.
  • TreeSet использует compareTo (определяется Comparable) или compare (определяется Comparator). Имейте в виду, что сравнение должно соответствовать equals. См. TreeSet JavaDocs для получения дополнительной информации.

Также имейте в виду, что если вы переопределяете equals, вы должны переопределить hashCode так, чтобы два объекта equals имели одинаковый хэш-код.

Ответ 8

Обычным способом сделать это было бы преобразование в набор, а затем обратно в список. Но вы можете получить представление о функциональной Java. Если вам понравился Lamdaj, вам понравится FJ.

recipients = recipients
             .sort(recipientOrd)
             .group(recipientOrd.equal())
             .map(List.<Recipient>head_());

Вам нужно будет определить порядок для получателей, recipientOrd. Что-то вроде:

Ord<Recipient> recipientOrd = ord(new F2<Recipient, Recipient, Ordering>() {
  public Ordering f(Recipient r1, Recipient r2) {
    return stringOrd.compare(r1.getEmailAddress(), r2.getEmailAddress());
  }
});

Работает, даже если у вас нет контроля над equals() и hashCode() в классе Recipient.