Before I post this question, I found somehow similar question posted here. But the answer was based on a String. However, I have a different situation here. I am not trying to remove String but another object called AwardYearSource. This class has an int attribute called year. So I want to remove duplicates based on the year. i.e if there is year 2010 mentioned more than once, I want to remove that AwardYearSource object. How can I do that?
问题:
回答1:
The simplest way to remove elements based on a field is as follows (preserving order):
Map<Integer, AwardYearSource> map = new LinkedHashMap<>();
for (AwardYearSource ays : list) {
map.put(ays.getYear(), ays);
}
list.clear();
list.addAll(map.values());
回答2:
Another way would be to override hashCode()
and equals(Object obj)
for your object. Since it just has one field you want to use to determine equality, this is pretty straightforward. Something like:
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;
}
Then you can just stick all of the objects into a Set
to remove duplicates:
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);
}
回答3:
Fairly simply. Although something bugs me about the map versions (not that I doubt they'd work, it just seems like overkill, somehow - although this version isn't necessarily any better in that regard).
Answer is functional, and threadsafe (assuming AwardYearSource
is immutable).
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;
}
回答4:
You could use a map and store your objects with the year as a key:
Map<Integer, AwardYearSource> map = new HashMap<Integer, AwardYearSource>();
map.put(someAwardYearSource1.getYear(), someAwardYearSource1);
map.put(someAwardYearSource2.getYear(), someAwardYearSource2);
etc.
At the end the map will contain unique values by year, which you can call with the values method:
Collection<AwardYearSource> noDups = map.values();
回答5:
Create a HashMap object with int as the key type and your class as the value type. Then iterate over the list and insert each element to the map using:
mymap.put(source.year, source);
Then remove all elements from the origianl list and iterate over the map and insert each element to the list.
回答6:
If your AwardYearSource class overrides equals and hashcode methods (Eclipse can generate both), then you can add them to a Set. The Set will not contain any duplicates.
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);
}
}
The output is [2000]. Only one item in the set.
回答7:
Set<Integer> set = new HashSet<>();
list.removeIf(i -> set.contains(i.getYear()) ? true : !set.add(i.getYear()));
This should help wherein, duplication is decided based on certain property (or combination of properties), year in this case. Hope this helps.