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

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

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

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

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

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

Ответы [ 17 ]

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

Вот полный код, который работает для этого сценария:

class Blog {
    private String title;
    private String author;
    private String url;
    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    public String getUrl() {
        return url;
    }

    public void setUrl(String url) {
        this.url = url;
    }

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    private String description;    

    Blog(String title, String author, String url, String description)
    {
        this.title = title;
        this.author = author;
        this.url = url;
        this.description = description; 
    }
    @Override
    public boolean equals(Object obj) {
        // TODO Auto-generated method stub
        if(obj instanceof Blog)
        {
            Blog temp = (Blog) obj;
            if(this.title == temp.title && this.author== temp.author && this.url == temp.url && this.description == temp.description)
                return true;
        }
        return false;

    }
    @Override
    public int hashCode() {
        // TODO Auto-generated method stub

        return (this.title.hashCode() + this.author.hashCode() + this.url.hashCode() + this.description.hashCode());        
    }
}

Вот основная функция, которая удалит дубликаты:

public static void main(String[] args) {
    Blog b1 = new Blog("A", "sam", "a", "desc");
    Blog b2 = new Blog("B", "ram", "b", "desc");
    Blog b3 = new Blog("C", "cam", "c", "desc");
    Blog b4 = new Blog("A", "sam", "a", "desc");
    Blog b5 = new Blog("D", "dam", "d", "desc");
    List<Blog> list = new ArrayList();
    list.add(b1);
    list.add(b2);
    list.add(b3);
    list.add(b4);       
    list.add(b5);

    //Removing Duplicates;
    Set<Blog> s= new HashSet<Blog>();
    s.addAll(list);         
    list = new ArrayList<Blog>();
    list.addAll(s);        
    //Now the List has only the identical Elements
}
11 голосов
/ 13 июля 2011

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

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

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

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

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

Используйте набор:

yourList = new ArrayList<Blog>(new LinkedHashSet<Blog>(yourList));

Это создаст список без дубликатов, и порядок элементов будет такой же, как в оригинальном списке.

Только не забудьте реализовать hashCode () и equals () для вашего класса Blog.

4 голосов
/ 13 июля 2011
  1. переопределить hashCode() и equals(..), используя эти 4 поля
  2. use new HashSet<Blog>(blogList) - это даст вам Set, который не имеет дубликатов по определению

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

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

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

2 голосов
/ 23 апреля 2016

Вот один из способов удаления дублирующегося объекта.

Класс блога должен быть примерно таким или похожим, например, как pojo

public class Blog {

    private String title;
    private String author;
    private String url;
    private String description;

    private int hashCode;



    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
       this.title = title;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
    public String getUrl() {
        return url;
    }
    public void setUrl(String url) {
        this.url = url;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }

    @Override
    public boolean equals(Object obj) {

        Blog blog = (Blog)obj;

        if(title.equals(blog.title) &&
                author.equals(blog.author) &&
                url.equals(blog.url) &&
                description.equals(blog.description))
        {
            hashCode = blog.hashCode;
            return true;
        }else{
            hashCode = super.hashCode();
            return false;
        }
    }

}

И использовать его таким образом, чтобы удалять дубликаты.объекты.Ключевой структурой данных здесь является Set и LinkedHashSet.Он удалит дубликаты, а также сохранит порядок ввода

    Blog blog1 = new Blog();
    blog1.setTitle("Game of Thrones");
    blog1.setAuthor("HBO");
    blog1.setDescription("The best TV show in the US");
    blog1.setUrl("www.hbonow.com/gameofthrones");

    Blog blog2 = new Blog();
    blog2.setTitle("Game of Thrones");
    blog2.setAuthor("HBO");
    blog2.setDescription("The best TV show in the US");
    blog2.setUrl("www.hbonow.com/gameofthrones");

    Blog blog3 = new Blog();
    blog3.setTitle("Ray Donovan");
    blog3.setAuthor("Showtime");
    blog3.setDescription("The second best TV show in the US");
    blog3.setUrl("www.showtime.com/raydonovan");

    ArrayList<Blog> listOfBlogs = new ArrayList<>();

    listOfBlogs.add(blog1);
    listOfBlogs.add(blog2);
    listOfBlogs.add(blog3);


    Set<Blog> setOfBlogs = new LinkedHashSet<>(listOfBlogs);

    listOfBlogs.clear();
    listOfBlogs.addAll(setOfBlogs);

    for(int i=0;i<listOfBlogs.size();i++)
        System.out.println(listOfBlogs.get(i).getTitle());

Выполнение этого должно вывести

Game of Thrones
Ray Donovan

Второй будет удален, поскольку он является дубликатом первого объекта.

1 голос
/ 26 марта 2017

используйте этот код

 public List<Blog> removeDuplicates(List<Blog> list) {
    // Set set1 = new LinkedHashSet(list);
    Set set = new TreeSet(new Comparator() {

        @Override
        public int compare(Object o1, Object o2) {
            if (((Blog) o1).get().equalsIgnoreCase(((Blog) o2).getId()) /*&&
                    ((Blog)o1).getName().equalsIgnoreCase(((Blog)o2).getName())*/) {
                return 0;
            }
            return 1;
        }
    });
    set.addAll(list);

    final List newList = new ArrayList(set);
    return newList;
}
1 голос
/ 13 июля 2011

Если ваш класс Blog имеет соответствующий метод equals(), определенный для него, самый простой способ - просто создать Set из вашего списка, который автоматически удалит дубликаты:

List<Blog> blogList = ...; // your initial list
Set<Blog> noDups = new HashSet<Blog>(blogList)

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

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

1 голос
/ 13 марта 2015
    import java.util.ArrayList;

    import java.util.HashSet;

    class Person

{
    public int age;
    public String name;
    public int hashCode()
    {
       // System.out.println("In hashcode");
        int hashcode = 0;
        hashcode = age*20;
        hashcode += name.hashCode();
        System.out.println("In hashcode :  "+hashcode);
        return hashcode;
    }
     public boolean equals(Object obj)
        {
            if (obj instanceof Person)
                {
                    Person pp = (Person) obj;
                    boolean flag=(pp.name.equals(this.name) && pp.age == this.age); 
                    System.out.println(pp);
                    System.out.println(pp.name+"    "+this.name);
                    System.out.println(pp.age+"    "+this.age);
                    System.out.println("In equals : "+flag);
                    return flag;
                }
                else 
                    {
                    System.out.println("In equals : false");
                        return false;
                    }
         }
    public void setAge(int age)
    {
        this.age=age;
    }
    public int getAge()
    {
        return age;
    }
    public void setName(String name )
    {
        this.name=name;
    }
    public String getName()
    {
        return name;
    }
    public String toString()
    {
        return "[ "+name+", "+age+" ]";
    }
}
class ListRemoveDuplicateObject 
{
    public static void main(String[] args) 
    {
        ArrayList<Person> al=new ArrayList();

            Person person =new Person();
            person.setName("Neelesh");
            person.setAge(26);
            al.add(person);

            person =new Person();
            person.setName("Hitesh");
            person.setAge(16);
            al.add(person);

            person =new Person();
            person.setName("jyoti");
            person.setAge(27);
            al.add(person);

            person =new Person();
            person.setName("Neelesh");
            person.setAge(60);
            al.add(person);

            person =new Person();
            person.setName("Hitesh");
            person.setAge(16);
            al.add(person);

            person =new Person();
            person.setName("Mohan");
            person.setAge(56);
            al.add(person);

            person =new Person();
            person.setName("Hitesh");
            person.setAge(16);
            al.add(person);

        System.out.println(al);
        HashSet<Person> al1=new HashSet();
        al1.addAll(al);
        al.clear();
        al.addAll(al1);
        System.out.println(al);
    }
}

выход

[[Нилеш, 26], [Хитеш, 16], [Джйоти, 27], [Нилеш, 60], [Хитеш, 16], [Мохан, 56], [Хитеш, 16]]
В хэш-код: -801018364
В хеш-коде: -2133141913
В хэш-коде: 101608849
В хеш-коде: -801017684
В хеш-коде: -2133141913
[Hitesh, 16]
Hitesh Hitesh
16 16
В равных: true
В хэш-код: 74522099
В хэш-коде: -2133141913
[Hitesh, 16]
Hitesh Hitesh
16 16
В равных: true
[[Нилеш, 60], [Нилеш, 26], [Мохан, 56], [Джйоти, 27], [Хитеш, 16]]

1 голос
/ 21 декабря 2012

Я пытался сделать несколько способов удаления дубликатов из списка объектов Java
Некоторые из них
1. Переопределите методы equals и hashCode и преобразуйте список в набор, передав список в конструктор класса set, и удалите и добавьте все
2. Запустите 2 указателя и удалите дублирует вручную, запустив 2 для циклов один внутри другого, как мы обычно делали на языке C для массивов
3. Напишите анонимный класс Comparator для bean-компонента и выполните Collections.sort, а затем запустите 2 указателя для удаления в прямом направлении. .



Более того, мое требование заключалось в том, чтобы удалить почти 1 миллион дубликатов с почти 5 миллионов объектов.
Поэтому после стольких испытаний я остановился на третьем варианте, который, на мой взгляд, является наиболее эффективным и действенным, и он оказался оцененным в рамках секунды, в то время как другие 2 опции почти занимают от 10 до 15 минут.
Первая и вторая опции очень неэффективны, потому что когда мои объекты увеличивают время, необходимое для удаления дубликатов, экспоненциально увеличиваются.

Итак, наконец, третья вариант самый лучший.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...