我必须删除List中的重复对象。 它是来自对象博客的列表,如下所示:
public class Blog {
private String title;
private String author;
private String url;
private String description;
...
}
重复对象是一个对象,其标题,作者,网址和描述等于其他对象。
我不能改变这个对象。我不能把新的方法放在上面。
我该怎么做?
答案 0 :(得分:16)
以下是适用于此场景的完整代码:
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
}
答案 1 :(得分:11)
如果你不能编辑类的来源(为什么不呢?),那么你需要迭代列表并根据提到的四个标准(“标题,作者,网址和描述”)比较每个项目。
要以高效的方式执行此操作,我会创建一个新类,例如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()
。
答案 2 :(得分:10)
确保Blog
已定义方法equals(Object)
和hashCode()
,然后addAll(list)
为new HashSet()
或new LinkedHashSet()
,如果订单为重要的。
更好的是,从一开始就使用Set
而不是List
,因为您显然不需要重复,最好是您的数据模型反映出来而不是必须在事实。
答案 3 :(得分:4)
hashCode()
和equals(..)
new HashSet<Blog>(blogList)
- 这将为您提供Set
,根据定义没有重复项更新:由于您无法更改类,因此这是一个O(n ^ 2)解决方案:
如果您使用外部化HashSet
和hashCode()
方法提供equals(..)
数据结构,则可以提高效率。
答案 4 :(得分:4)
使用set:
yourList = new ArrayList<Blog>(new LinkedHashSet<Blog>(yourList));
这将创建没有重复的列表,元素顺序将与原始列表中一样。
请不要忘记为您的班级Blog实现hashCode()和equals()。
答案 5 :(得分:2)
以下是删除重复对象的一种方法。
博客类应该像这样或类似的东西,比如适当的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
第二个将被删除,因为它是第一个对象的副本。
答案 6 :(得分:1)
您可以使用distinct删除重复项
List<Blog> blogList = ....// add your list here
blogList.stream().distinct().collect(Collectors.toList());
答案 7 :(得分:1)
您可以使用标题,作者,网址和说明覆盖equals()
方法。 (和hashCode()
,因为如果你覆盖一个,你应该覆盖另一个)。然后使用HashSet
类型的<blog>
。
答案 8 :(得分:1)
您需要的第一步是实现equals方法并比较您的字段。之后,步骤会有所不同。
您可以使用:if(!list2.contains(item))创建一个新的空列表并循环遍历原始列表,然后执行添加。
另一种快速的方法是将它们全部塞进一个Set并将它们拉回到List中。这是有效的,因为集合不允许重复开始。
答案 9 :(得分:1)
我不能改变这个对象。我不能把新的方法放在上面。
我该怎么做?
如果你还意味着我如何使对象不可变并阻止子类化:使用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)
添加到该集合中。最后,您应该只在集合中拥有唯一(包装)博客。
答案 10 :(得分:1)
如果您的Blog
班级上定义了适当的equals()
方法,最简单的方法就是从列表中创建Set
,这会自动删除重复项:
List<Blog> blogList = ...; // your initial list
Set<Blog> noDups = new HashSet<Blog>(blogList)
这可能会透明地与其余代码一起工作 - 例如,如果您只是迭代内容,那么Collection
的任何实例都可以与另一个实例一样好。 (如果迭代顺序很重要,那么您可能更喜欢使用LinkedHashSet
,这将保留列表的原始顺序。)
如果你真的需要结果是List
然后保持简单的方法,你可以通过包裹ArrayList
(或类似的)再次直接转换它。如果你的藏品相对较小(比如说不到一千个元素),那么这种方法的明显效率低下可能并不重要。
答案 11 :(得分:1)
我尝试了几种从java对象列表中删除重复项的方法
其中一些是:1。覆盖equals和hashCode方法,并通过将列表传递给set类构造函数将列表转换为集合,然后删除并添加全部.2。运行2指针并通过运行2 for循环手动删除副本一个在另一个内部,就像我们在C语言中为数组所做的那样.3。为bean编写一个匿名的Comparator类并执行Collections.sort,然后运行2个指向向前移动。
而且我的要求更多的是从近500万个物体中移除近100万个重复物。
因此经过这么多试验后,我得到了第三种选择,我觉得这是最有效和最有效的方法,结果证明是评估在几秒钟内,其他2个选项几乎需要10到15分钟。
第一和第二选项非常无效,因为当我的对象增加了删除重复项所需的时间以指数方式增加。
所以最后第三个选项是最好的。
答案 12 :(得分:1)
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);
}
}
输出
[[Neelesh,26],[Hitesh,16],[jyoti,27],[Neelesh,60],[Hitesh,16],[Mohan,56],[Hitesh,16]]
在哈希码中:-801018364
在哈希码中:-2133141913
在哈希码中:101608849
在哈希码中:-801017684
在哈希码中:-2133141913
[Hitesh,16]
Hitesh Hitesh
16 16
等于:真实
在哈希码:74522099
在哈希码中:-2133141913
[Hitesh,16]
Hitesh Hitesh
16 16
等于:真实
[[Neelesh,60],[Neelesh,26],[Mohan,56],[jyoti,27],[Hitesh,16]]
答案 13 :(得分:1)
使用此代码
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;
}
答案 14 :(得分:1)
这可以使用属性从逻辑上解决。这里有一个称为键的属性。
List<Object> objectList = new ArrayList<>();
List<String> keyList = new ArrayList<>();
objectList.forEach( obj -> {
if(keyList.contains(unAvailabilityModel.getKey()))
objectList.remove(unAvailabilityModel);
else
keyList.add(unAvailabilityModel.getKey();
});
return objectList;
答案 15 :(得分:0)
最简单,最有效的方法是允许eclipse生成并覆盖equals和hashcode方法。只需在提示时选择要检查重复项的属性,您应该全部设置。
此外,一旦列表准备就绪,将其放入一个集合中,你就可以复制它了。
答案 16 :(得分:0)
如果由于某些原因您不想覆盖equals
方法,而又想基于多个属性删除重复项,那么我们可以创建一个通用方法来做到这一点。
我们可以编写2个版本:
1。修改原始列表:
@SafeVarargs
public static <T> void removeDuplicatesFromList(List<T> list, Function<T, ?>... keyFunctions) {
Set<List<?>> set = new HashSet<>();
ListIterator<T> iter = list.listIterator();
while(iter.hasNext()) {
T element = iter.next();
List<?> functionResults = Arrays.stream(keyFunctions)
.map(function -> function.apply(element))
.collect(Collectors.toList());
if(!set.add(functionResults)) {
iter.remove();
}
}
}
2。返回新列表:
@SafeVarargs
public static <T> List<T> getListWithoutDuplicates(List<T> list, Function<T, ?>... keyFunctions) {
List<T> result = new ArrayList<>();
Set<List<?>> set = new HashSet<>();
for(T element : list) {
List<?> functionResults = Arrays.stream(keyFunctions)
.map(function -> function.apply(element))
.collect(Collectors.toList());
if(set.add(functionResults)) {
result.add(element);
}
}
return result;
}
在两种情况下,我们都可以考虑任意数量的属性。
例如,要基于4个属性title
,author
,url
和description
删除重复项:
removeDuplicatesFromList(blogs, Blog::getTitle, Blog::getAuthor, Blog::getUrl, Blog::getDescription);
该方法通过利用equals
的{{1}}方法来工作,该方法将检查其元素的相等性。在我们的例子中,List
的元素是从传递的getter中获取的值,我们可以将该列表用作functionResults
的元素来检查重复项。
完整示例:
Set
答案 17 :(得分:0)
我们还可以使用Comparator检查重复的元素。示例代码如下,
私有布尔checkDuplicate(列出学生DTO){
2909
答案 18 :(得分:0)
建议重写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()
的第三个参数是merge Function(功能接口),用于解决与同一键关联的值之间的冲突。
答案 19 :(得分:0)
创建一个包装Blog对象的新类,并提供所需的相等/哈希码方法。为了获得最大效率,我将在包装器上添加两个静态方法,一个用于转换博客列表 - &gt; Blog Wrapper列表和另一个转换Blog Wrapper列表 - &gt;博客列表。然后你会:
Blog Wrapper的代码将是这样的:
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);
很明显,您可以使上述代码更有效,特别是通过使Blog Wrapper上的wrap和unwrap方法采用集合而不是列表。
包装Blog类的另一种方法是使用像BCEL这样的字节码操作库来实际更改Blog的equals和hashcode方法。但是,当然,如果它们需要原始的equals / hashcode行为,那么这可能会给代码的其余部分带来意想不到的后果。
答案 20 :(得分:0)
首先覆盖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);
}
}