Подтвердить что ты не робот

Как удалить дубликаты из списка на основе пользовательского java-объекта, а не примитивного типа?

Прежде чем опубликовать этот вопрос, я нашел как-то похожий вопрос, размещенный здесь. Но ответ был основан на String. Однако здесь у меня другая ситуация. Я не пытаюсь удалить String, а другой объект называется AwardYearSource. Этот класс имеет атрибут int year. Поэтому я хочу удалить дубликаты в зависимости от года. Если 2010 год упоминается не один раз, я хочу удалить этот объект AwardYearSource. Как я могу это сделать?

4b9b3361

Ответ 1

Самый простой способ удаления элементов, основанных на поле, состоит в следующем (сохранение порядка):

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

Ответ 2

Другим способом было бы переопределить 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);
}

Ответ 3

Довольно просто. Хотя что-то меня беспокоит о версиях карт (не то, что я сомневаюсь, что они сработают, это как-то похоже на перебор, так или иначе), хотя эта версия не обязательно лучше в этом отношении). Ответ является функциональным, и потокобезопасность (предполагая, что AwardYearSource является неизменной).

public static List<AwardYearSource> removeDuplicateYears(
                                          final Collection<AwardYearSource> awards) {
    final ArrayList<AwardYearSource> input = new ArrayList<AwardYearSource>(awards);
    // If there 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

Вы можете использовать карту и хранить свои объекты с годом в качестве ключа:

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

etc.

В конце карта будет содержать уникальные значения по годам, которые вы можете вызвать с помощью метода значений:

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

Ответ 5

Создайте объект HashMap с int как тип ключа и ваш класс как тип значения. Затем перейдите по списку и вставьте каждый элемент в карту, используя:

mymap.put(source.year, source);

Затем удалите все элементы из списка origianl и выполните итерацию по карте и вставьте каждый элемент в список.

Ответ 6

Если ваш класс AwardYearSource переопределяет равные и методы 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]. Только один элемент в наборе.

Ответ 7

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

Это должно помочь, когда дублирование определяется на основе определенного свойства (или комбинации свойств), год в этом случае. Надеюсь, это поможет.