Мне нужно удалить повторяющиеся объекты в списке. Это список из блога объекта, который выглядит следующим образом:
public class Blog {
private String title;
private String author;
private String url;
private String description;
...
}
Дублированный объект - это объект, у которого заголовок, автор, URL-адрес и описание совпадают с другим объектом.
И я не могу изменить объект. Я не могу добавить к нему новые методы.
Как мне это сделать?
Если вы не можете редактировать источник класса (почему бы и нет?), То вам нужно перебрать список и сравнить каждый элемент на основе четырех упомянутых критериев («заголовок, автор, URL и описание»).
Чтобы сделать это быстрым способом, я бы создал новый класс, что-то вроде BlogKey
, который содержит эти четыре элемента, и , который должным образом реализует equals()
и hashCode()
. Затем вы можете перебирать исходный список, создавая BlogKey
для каждого и добавляя к HashMap
:
Map<BlogKey, Blog> map = new HashMap<BlogKey, Blog>();
for (Blog blog : blogs) {
BlogKey key = createKey(blog);
if (!map.containsKey(key)) {
map.put(key, blog);
}
}
Collection<Blog> uniqueBlogs = map.values();
. Однако гораздо проще всего просто отредактировать исходный код Blog
. так что он правильно реализует equals()
и hashCode()
.
Первый шаг, который вам нужен, это реализовать метод equals и сравнить ваши поля. После этого шаги меняются.
Вы можете создать новый пустой список и перебрать оригинал, используя: if (! List2.contains (item)), а затем сделать добавление.
Еще один быстрый способ сделать это - собрать их всех в набор и вернуть обратно в список. Это работает, потому что наборы не позволяют дубликатам начинаться с.
Самый простой и эффективный способ - позволить затмению генерировать и переопределять метод равенства и хэш-кода. Просто выберите атрибуты, которые будут проверены на наличие дубликатов, когда вам будет предложено, и все будет готово.
Также, как только список будет готов, поместите его в набор, и вы удалите дубликаты.
Сначала переопределите метод equals()
:
@Override
public boolean equals(Object obj)
{
if(obj == null) return false;
else if(obj instanceof MyObject && getTitle() == obj.getTitle() && getAuthor() == obj.getAuthor() && getURL() == obj.getURL() && getDescription() == obj.getDescription()) return true;
else return false;
}
, а затем используйте:
List<MyObject> list = new ArrayList<MyObject>;
for(MyObject obj1 : list)
{
for(MyObject obj2 : list)
{
if(obj1.equals(obj2)) list.remove(obj1); // or list.remove(obj2);
}
}
И я не могу изменить объект. Я не могу поставить новые методы на это.
Как мне это сделать?
В случае, если вы также хотите сказать, как сделать объект неизменным и предотвратить создание подклассов: используйте ключевое слово final
public final class Blog { //final classes can't be extended/subclassed
private final String title; //final members have to be set in the constructor and can't be changed
private final String author;
private final String url;
private final String description;
...
}
Редактировать: Я только что видел некоторые ваши комментарии, и кажется, что вы хотите изменить класс, но не можете (сторонняя организация, я полагаю).
Для предотвращения дубликатов вы можете использовать оболочку, которая реализует соответствующие equals()
и hashCode()
, а затем использовать подход Set
, упомянутый другими:
class BlogWrapper {
private Blog blog; //set via constructor etc.
public int hashCode() {
int hashCode = blog.getTitle().hashCode(); //check for null etc.
//add the other hash codes as well
return hashCode;
}
public boolean equals(Object other) {
//check if both are BlogWrappers
//remember to check for null too!
Blog otherBlog = ((BlogWrapper)other).getBlog();
if( !blog.getTitle().equals(otherBlog.getTitle()) {
return false;
}
... //check other fields as well
return true
}
}
Обратите внимание, что это просто грубая и простая версия и не содержит обязательных нулевых проверок.
Наконец, используйте Set<BlogWrapper>
, переберите все блоги и попробуйте добавить new BlogWrapper(blog)
в набор. В конце у вас должны быть только уникальные (завернутые) блоги в наборе.
hashCode()
и equals(..)
, используя эти 4 поля new HashSet<Blog>(blogList)
- это даст вам Set
, который не имеет дубликатов по определению Обновление: поскольку вы не можете изменить класс, вот решение O (n ^ 2):
Вы можете сделать это более эффективным, если предоставите структуру данных HashSet
с externalized hashCode()
и equals(..)
методы.
Убедитесь, что в Blog
определены методы equals(Object)
и hashCode()
, а затем addAll(list)
в new HashSet()
или new LinkedHashSet()
, если порядок важен.
Еще лучше, используйте Set
вместо List
с самого начала, поскольку вы, очевидно, не хотите дубликатов, лучше, чтобы ваша модель данных отражала это, а не удаляла их по факту.