Как удалить повторяющиеся объекты в Список без equals / hashcode?

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

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

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

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

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

27
задан moffeltje 12 March 2018 в 17:16
поделиться

7 ответов

Если вы не можете редактировать источник класса (почему бы и нет?), То вам нужно перебрать список и сравнить каждый элемент на основе четырех упомянутых критериев («заголовок, автор, 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().

12
ответ дан 28 November 2019 в 04:53
поделиться

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

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

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

1
ответ дан 28 November 2019 в 04:53
поделиться

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

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

0
ответ дан 28 November 2019 в 04:53
поделиться

Сначала переопределите метод 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);
    }
}
0
ответ дан 28 November 2019 в 04:53
поделиться

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

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

В случае, если вы также хотите сказать, как сделать объект неизменным и предотвратить создание подклассов: используйте ключевое слово 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
ответ дан 28 November 2019 в 04:53
поделиться
  1. переопределяют hashCode() и equals(..), используя эти 4 поля
  2. используют new HashSet<Blog>(blogList) - это даст вам Set, который не имеет дубликатов по определению

Обновление: поскольку вы не можете изменить класс, вот решение O (n ^ 2):

  • создайте новый список
  • итерируйте первый список
  • во внутреннем цикле итерируйте второй список и проверьте, есть ли в нем элемент с такими же полями

Вы можете сделать это более эффективным, если предоставите структуру данных HashSet с externalized hashCode() и equals(..) методы.

4
ответ дан 28 November 2019 в 04:53
поделиться

Убедитесь, что в Blog определены методы equals(Object) и hashCode(), а затем addAll(list) в new HashSet() или new LinkedHashSet(), если порядок важен.

Еще лучше, используйте Set вместо List с самого начала, поскольку вы, очевидно, не хотите дубликатов, лучше, чтобы ваша модель данных отражала это, а не удаляла их по факту.

10
ответ дан 28 November 2019 в 04:53
поделиться
Другие вопросы по тегам:

Похожие вопросы: