Как удалить дубликаты объектов в списке <MyObject>без равенства / хэш-кода? - PullRequest
23 голосов
/ 13 июля 2011

Я должен удалить дубликаты объектов в списке.Это список из объекта Blog, который выглядит следующим образом:

public class Blog {
    private String title;
    private String author;
    private String url;
    private String description;
    ...
}

Дублированный объект - это объект, заголовок, автор, URL и описание которого совпадают с другим объектом.

И яне может изменить объект.Я не могу использовать новые методы.

Как мне это сделать?

Ответы [ 17 ]

1 голос
/ 13 июля 2011

И я не могу изменить объект. Я не могу поставить новые методы на это.

Как мне это сделать?

Если вы также имеете в виду, как сделать объект неизменным и предотвратить создание подклассов: используйте ключевое слово 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) в набор. В конце у вас должны быть только уникальные (завернутые) блоги в наборе.

1 голос
/ 13 июля 2011

Первый шаг, который вам нужен, это реализовать метод equals и сравнить ваши поля.После этого шаги могут отличаться.

Вы можете создать новый пустой список и перейти к оригиналу, используя: if (! List2.contains (item)), а затем выполнить добавление.

ДругойБыстрый способ сделать это - собрать их всех в набор и вернуть обратно в список.Это работает, потому что наборы не позволяют дубликатам начинаться с.

1 голос
/ 13 июля 2011

Вы можете переопределить метод equals(), используя заголовок, автора, URL и описание.(и hashCode(), поскольку, если вы переопределяете одно, вы должны переопределить другое).Затем используйте HashSet типа <blog>.

0 голосов
/ 10 июля 2019

Рекомендуется переопределить equals() и hashCode() для работы с коллекциями на основе хеша, включая HashMap, HashSet и Hashtable. Таким образом, вы можете легко удалить дубликаты, запустив HashSet объект со списком блогов.

List<Blog> blogList = getBlogList();
Set<Blog> noDuplication = new HashSet<Blog>(blogList);

Но благодаря Java 8, который имеет очень чистую версию для этого, как вы упоминали, вы не можете изменить код для добавления equals() и hashCode()

Collection<Blog> uniqueBlogs = getUniqueBlogList(blogList);

private Collection<Blog> getUniqueBlogList(List<Blog> blogList) {
    return blogList.stream()
            .collect(Collectors.toMap(createUniqueKey(), Function.identity(), (blog1, blog2) -> blog1))
            .values();
}
List<Blog> updatedBlogList = new ArrayList<>(uniqueBlogs);

Третий параметр Collectors.toMap() - это функция слияния (функциональный интерфейс), используемая для разрешения конфликтов между значениями, связанными с одним и тем же ключом.

0 голосов
/ 16 апреля 2014

Самый простой и эффективный способ - позволить eclipse генерировать и переопределять метод equals и hashcode.Просто выберите атрибуты, которые будут проверены на наличие дубликатов, когда вам будет предложено, и все будет готово.

Также, когда список будет готов, поместите его в набор и удалите дубликаты.

0 голосов
/ 13 июля 2011

Создайте новый класс, который обернет ваш объект Blog и предоставит необходимый вам метод равенства / хэш-кода.Для максимальной эффективности я бы добавил два статических метода в обертку: один для преобразования списка блогов -> список блогов и другой, чтобы конвертировать список блогов -> список блогов.Тогда вы бы:

  1. преобразовали свой список блогов в список оболочек блогов
  2. добавили бы список оболочек блогов в набор хэшей
  3. Получить сжатый список оболочек блогов обратноиз хэш-набора
  4. Преобразование списка оболочки блога в список блогов

Код для оболочки блога будет выглядеть примерно так:

import java.util.ArrayList;
import java.util.List;

public class BlogWrapper {
    public static List<Blog> unwrappedList(List<BlogWrapper> blogWrapperList) {
        if (blogWrapperList == null)
            return new ArrayList<Blog>(0);

        List<Blog> blogList = new ArrayList<Blog>(blogWrapperList.size());
        for (BlogWrapper bW : blogWrapperList) {
            blogList.add(bW.getBlog());
        }

        return blogList;
    }

    public static List<BlogWrapper> wrappedList(List<Blog> blogList) {
        if (blogList == null)
            return new ArrayList<BlogWrapper>(0);

        List<BlogWrapper> blogWrapperList = new ArrayList<BlogWrapper>(blogList
                .size());
        for (Blog b : blogList) {
            blogWrapperList.add(new BlogWrapper(b));
        }

        return blogWrapperList;
    }

    private Blog blog = null;

    public BlogWrapper() {
        super();
    }

    public BlogWrapper(Blog aBlog) {
        super();
        setBlog(aBlog);
    }

    public boolean equals(Object other) {
        // Your equality logic here
        return super.equals(other);
    }

    public Blog getBlog() {
        return blog;
    }

    public int hashCode() {
        // Your hashcode logic here
        return super.hashCode();
    }

    public void setBlog(Blog blog) {
        this.blog = blog;
    }
}

И вы могли быиспользуйте это так:

List<BlogWrapper> myBlogWrappers = BlogWrapper.wrappedList(your blog list here);
Set<BlogWrapper> noDupWrapSet = new HashSet<BlogWrapper>(myBlogWrappers);
List<BlogWrapper> noDupWrapList = new ArrayList<BlogWrapper>(noDupSet);
List<Blog> noDupList = BlogWrapper.unwrappedList(noDupWrapList);

Совершенно очевидно, что вы можете сделать приведенный выше код более эффективным, в частности, заставив методы wrap и unwrap в Blog Wrapper принимать коллекции вместо списков.

АльтернативаПуть к переносу класса Blog заключался бы в использовании библиотеки манипулирования байт-кодом, такой как BCEL , чтобы фактически изменить метод equals и hashcode для Blog.Но, конечно, это может иметь непредвиденные последствия для остальной части вашего кода, если они требуют исходного поведения equals / hashcode.

0 голосов
/ 13 июля 2011

Первое переопределение 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);
    }
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...