Отберите все дубликаты в наборе
Я использую Set, чтобы изолировать уникальные значения списка (в этом случае я получаю набор баллов):
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
Это вернет набор уникальных точек, но для каждого элемента в listToCull я бы хотел проверить следующее: если есть дубликат, отберите все дублирующиеся элементы. Другими словами, я хочу, чтобы pointSet представлял набор элементов в listToCull, которые уже являются уникальными (у каждого элемента в pointSet не было дубликатов в listToCull). Любые идеи о том, как реализовать?
РЕДАКТИРОВАТЬ - Я думаю, мой первый вопрос нуждается в уточнении. Ниже приведен код, который будет выполнять то, что я прошу, но я хотел бы знать, есть ли более быстрый путь. Предполагая, что listToCull представляет собой список PVectors с дубликатами:
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
List<PVector> uniqueItemsInListToCull = new ArrayList<PVector>();
for(PVector pt : pointSet){
int counter=0;
for(PVector ptCheck : listToCull){
if(pt==ptCheck){
counter++;
}
}
if(counter<2){
uniqueItemsInListToCull.add(pt);
}
}
uniqueItemsInListToCull будет отличаться от pointSet. Я хотел бы сделать это без петель, если это возможно.
4 ответа
Вам придется заняться программированием самостоятельно: создать два пустых набора; Он будет содержать уникальные элементы, остальные дубликаты. Затем переберите элементы listToCull
, Для каждого элемента проверьте, находится ли он в дублирующем наборе. Если это так, игнорируйте это. В противном случае проверьте, находится ли он в уникальном наборе элементов. Если это так, удалите его и добавьте в набор дубликатов. В противном случае добавьте его в набор уникальных элементов.
Если твой PVector
класс хороший hashCode()
метод, HashSet
Они довольно эффективны, поэтому производительность не будет слишком плохой.
Непроверенные:
Set<PVector> uniques = new HashSet<>();
Set<PVector> duplicates = new HashSet<>();
for (PVector p : listToCull) {
if (!duplicates.contains(p)) {
if (uniques.contains(p)) {
uniques.remove(p);
duplicates.add(p);
}
else {
uniques.add(p);
}
}
}
Кроме того, вы можете использовать стороннюю библиотеку, которая предлагает Bag
или же MultiSet
, Это позволяет подсчитать, сколько вхождений каждого элемента в коллекции, а затем в конце отбросить все элементы, где количество отличается от 1.
Итак, вы хотите, чтобы pointSet содержал элементы в listToCull, у которых нет дубликатов? Это правильно?
Я был бы склонен создать карту, затем дважды выполнить итерацию по списку, в первый раз добавив нулевое значение для каждого PVector, во второй раз добавив единицу к значению для каждого PVector, поэтому в конце у вас есть карта с на счет. Теперь вас интересуют ключи карты, для которых значение точно равно единице.
Это не совсем эффективно - вы работаете с элементами списка больше, чем это абсолютно необходимо, но это довольно чисто и просто.
Хорошо, вот решение, которое я придумала, я уверен, что есть лучшие, но это работает для меня. Спасибо всем, кто дал направление!
Чтобы получить уникальные предметы, вы можете запустить Set, где listToCull - это список PVectors с дубликатами:
List<PVector> culledList = new ArrayList<PVector>();
Set<PVector> pointSet = new LinkedHashSet<PVector>(listToCull);
culledList.addAll(pointSet);
Чтобы пойти дальше, предположим, что вам нужен список, в котором вы удалили все элементы в listToCull, которые имеют дубликаты. Вы можете просмотреть список и проверить, есть ли он в наборе для каждого элемента. Это давайте сделаем один цикл, а не вложенный цикл:
Set<PVector> pointSet = new HashSet<PVector>(listToCull);
Set<PVector> removalList = new HashSet<PVector>();//list to remove
for (PVector pt : listToCull) {
if (pointSet.contains(pt)) {
removalList.add(pt);
}
else{
pointSet.add(pt);
}
}
pointSet.removeAll(removalList);
List<PVector> onlyUniquePts = new ArrayList<PVector>();
onlyUniquePts.addAll(pointSet);
То, что вы ищете, это intersection
:
При условии, что PVector
(ужасное имя, кстати) реализует hashCode()
а также equals()
правильно Set
устранит дубликаты.
Если вы хотите intersection
из List
и существующий Set
создать Set
от List
затем используйте Sets.intersection()
из Гуавы, чтобы получить общие для обоих наборов.
public static <E> Sets.SetView<E> intersection(Set<E> set1, Set<?> set2)
Возвращает неизменяемое представление пересечения двух множеств. Возвращенный набор содержит все элементы, которые содержатся в обоих вспомогательных наборах. Порядок итерации возвращаемого набора совпадает с порядком в set1. Результаты не определены, если set1 и set2 являются наборами, основанными на различных отношениях эквивалентности (как HashSet, TreeSet и keySet IdentityHashMap все).
Примечание. Возвращенное представление работает немного лучше, когда set1 является меньшим из двух наборов. Если у вас есть основания полагать, что один из ваших наборов, как правило, будет меньше другого, передайте его первым. К сожалению, поскольку этот метод устанавливает общий тип возвращаемого набора на основе типа первого переданного набора, это может в редких случаях вынудить вас выполнить приведение, например:
Set aFewBadObjects =... Установить manyBadStrings =...
// невозможно, чтобы строка не находилась в пересечении
SuppressWarnings("unchecked") Set badStrings = (Set) Sets.intersection( aFewBadObjects, manyBadStrings); Это прискорбно, но должно появляться очень редко.
Вы также можете сделать union
, complement
, difference
а также cartesianProduct
так же как filter
Очень легко.