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
Ответ 4
Java 8:
recipients = recipients.stream()
.distinct()
.collect(Collectors.toList());
См. java.util.stream.Stream#distinct
.
Ответ 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.
Ответ 9
Фактически lambdaj реализует эту функцию с помощью метода selectDistinctArgument
http://lambdaj.googlecode.com/svn/trunk/html/apidocs/ch/lambdaj/Lambda.html#selectDistinctArgument(java.lang.Object,%20A)