繁体   English   中英

如何根据自定义java对象而不是基本类型从列表中删除重复项?

[英]How to remove duplicates from a list based on a custom java object not a primitive type?

在我发布这个问题之前,我在这里发现了类似的问题。 但答案是基于一个字符串。 但是,我在这里有不同的情况。 我不是要删除String而是另一个名为AwardYearSource的对象。 该类有一个名为year的int属性。 所以我想删除基于年份的重复项。 即如果有不止一次提到的2010年,我想删除该AwardYearSource对象。 我怎样才能做到这一点?

基于字段删除元素的最简单方法如下(保留顺序):

Map<Integer, AwardYearSource> map = new LinkedHashMap<>();
for (AwardYearSource ays : list) {
  map.put(ays.getYear(), ays);
}
list.clear();
list.addAll(map.values());

另一种方法是覆盖equals(Object obj) hashCode()equals(Object obj) 由于它只需要一个字段来确定相等性,因此非常简单。 就像是:

public boolean equals(Object obj) {
  if (obj == null || !(obj instanceof AwardYearSource)) {
    return false;
  }
  return (this.year == ((AwardYearSource)obj).year);
}
public int hashCode() {
  return this.year;
}

然后,您可以将所有对象粘贴到Set以删除重复项:

Set<AwardYearSource> set = new Set<AwardYearSource>();

set.add(new AwardYearSource(2011));
set.add(new AwardYearSource(2012));
set.add(new AwardYearSource(2011));

for (AwardYearSource aws : set) {
  System.out.println(aws.year);
}

相当简单。 虽然有些东西让我对地图版本感到不满(不是我怀疑它们是否有效,但它似乎有点矫枉过正,不知怎的 - 虽然这个版本在这方面不一定更好)。
答案是功能性的,线程安全的(假设AwardYearSource是不可变的)。

public static List<AwardYearSource> removeDuplicateYears(
                                          final Collection<AwardYearSource> awards) {
    final ArrayList<AwardYearSource> input = new ArrayList<AwardYearSource>(awards);
    // If there's only one element (or none), guaranteed unique.
    if (input.size() <= 1) {
        return input;
    }
    final HashSet<Integer> years = new HashSet<Integer>(input.size(), 1);
    final Iterator<AwardYearSource> iter = input.iterator();
    while(iter.hasNext()) {
        final AwardYearSource award = iter.next();
        final Integer year = award.getYear();
        if (years.contains(year)) {
            iter.remove();
        } else {
            years.add(year);
        }
    }
    return input;       

}

您可以使用地图并将年份作为关键字存储在您的对象中:

Map<Integer, AwardYearSource> map = new HashMap<Integer, AwardYearSource>();
map.put(someAwardYearSource1.getYear(), someAwardYearSource1);
map.put(someAwardYearSource2.getYear(), someAwardYearSource2);

etc.

最后,地图将按年份包含唯一值,您可以使用values方法调用:

Collection<AwardYearSource> noDups = map.values();

创建一个HashMap对象,其中int作为键类型,您的类作为值类型。 然后迭代列表并使用以下方法将每个元素插入到地图中:

mymap.put(source.year, source);

然后从origianl列表中删除所有元素并迭代地图并将每个元素插入列表。

如果您的AwardYearSource类重写了equals和hashcode方法(Eclipse可以生成两者),那么您可以将它们添加到Set中。 该集不包含任何重复项。

public class AwardYearSource
{
    private final int year;

    public AwardYearSource(int year)
    {
        this.year = year;
    }

    @Override
    public int hashCode()
    {
        final int prime = 31;
        int result = 1;
        result = prime * result + year;
        return result;
    }

    @Override
    public boolean equals(Object obj)
    {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        AwardYearSource other = (AwardYearSource) obj;
        if (year != other.year)
            return false;
        return true;
    }

    @Override
    public String toString()
    {
        return String.valueOf(year);
    }


    public static void main(String[] args)
    {
        Set<AwardYearSource> set = new HashSet<AwardYearSource>();
        set.add(new AwardYearSource(2000));
        set.add(new AwardYearSource(2000));
        set.add(new AwardYearSource(2000));
        set.add(new AwardYearSource(2000));

        System.out.println(set);
    }
}

输出是[2000]。 集合中只有一个项目。

Set<Integer> set = new HashSet<>();
list.removeIf(i -> set.contains(i.getYear()) ? true : !set.add(i.getYear()));

这应该有帮助,其中,复制是基于某些属性(或属性的组合),在这种情况下的年份。 希望这可以帮助。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM