Как зайти в Даркнет?!
25th January, 01:11
8
0
Как в tkinter из поля ввода Entry получить значение в одну переменную и обновить строку кнопкой, затем получить ещё одно введённое значение и затем сложить их. Ниже пример кода
21st July, 19:00
898
0
Программа, которая создает фейковые сервера в поиске игровых серверов CS 1.6 Steam
21st March, 17:43
951
0
Очень долго работает Update запрос Oracle
27th January, 09:58
916
0
не могу запустить сервер на tomcat HTTP Status 404 – Not Found
21st January, 18:02
907
0
Где можно найти фрилансера для выполнения поступающих задач, на постоянной основе?
2nd December, 09:48
941
0
Разработка мобильной кроссплатформенной военной игры
16th July, 17:57
1726
0
период по дням
25th October, 10:44
3957
0
Пишу скрипты для BAS только на запросах
16th September, 02:42
3722
0
Некорректный скрипт для закрытия блока
14th April, 18:33
4614
0
прокидывать exception в блоках try-catch JAVA
11th March, 21:11
4382
0
Помогите пожалуйста решить задачи
24th November, 23:53
6087
0
Не понимаю почему не открывается детальное описание продукта
11th November, 11:51
4352
0
Нужно решить задачу по программированию на массивы
27th October, 18:01
4399
0
Метода Крамера С++
23rd October, 11:55
4309
0
помогите решить задачу на C++
22nd October, 17:31
4002
0
Помогите решить задачу на python с codeforces
22nd October, 11:11
4492
0
Python с нуля: полное руководство для начинающих
18th June, 13:58
2599
0
Как лучше всего сравнить две коллекции в Java и действовать по ним?
У меня есть две коллекции одного и того же объекта, Collection<Foo> oldSet и Collection<Foo> newSet . Необходимая логика заключается в следующем:
- если
fooнаходится в(*)oldSet, но неnewSet, вызовитеdoRemove(foo) - иначе, если
fooнаходится не вoldSet, а вnewSet, вызовитеdoAdd(foo) - в противном случае, если
fooнаходится в обеих коллекциях, но изменен, вызовитеdoUpdate(oldFoo, newFoo) - еще если
!foo.activated && foo.startDate >= now, то звонитеdoStart(foo) - еще если
foo.activated && foo.endDate <= now,doEnd(foo)звоните
( * ) "in" означает совпадение уникального идентификатора, но не обязательно содержимого.
Текущий (устаревший) код выполняет множество сравнений, чтобы вычислить removeSet , addSet , updateSet , startSet и endSet, а затем выполнить цикл для каждого элемента.
Код довольно грязный (отчасти потому, что я уже пропустил некоторую логику спагетти), и я пытаюсь его рефакторировать. Еще немного фоновой информации:
- Насколько я знаю,
oldSetиnewSetна самом деле подкрепленыArrayList - Каждый набор содержит менее 100 элементов, скорее всего, максимум 20
- Этот код вызывается часто (измеряется в millions/day),, хотя наборы редко отличаются
Мой вопрос:
- Если я преобразую
oldSetиnewSetвHashMap<Foo>(порядок здесь не имеет значения), с ключами IDs в качестве ключей, будет ли это облегчать чтение кода и его сравнение? Сколько времени & производительность памяти теряется при преобразовании? - Будет ли повторение двух наборов и выполнение соответствующей операции более эффективным и лаконичным?
Библиотека Apache commons.collections имеет класс CollectionUtils, который предоставляет easy-to-use методов для коллекции manipulation/checking,, таких как пересечение, различие и объединение.
Орг.apache.палата общин.коллекции.CollectionUtils API документы здесь .
Вы можете использовать Java 8 потоков, например
set1.stream().filter(s -> set2.contains(s)).collect(Collectors.toSet());
или устанавливает класс из гуавы :
Set<String> intersection = Sets.intersection(set1, set2);
Set<String> difference = Sets.difference(set1, set2);
Set<String> symmetricDifference = Sets.symmetricDifference(set1, set2);
Set<String> union = Sets.union(set1, set2);
Я создал аппроксимацию того, что, как мне кажется, вы ищете, просто используя фреймворк коллекций в Java. Честно говоря, я думаю, что это, вероятно, излишне, как указывает колода @Mike. Для такого небольшого набора элементов для сравнения и обработки я думаю, что массивы были бы лучшим выбором с процедурной точки зрения, но вот мое псевдокодированное (потому что я ленив) решение. У меня есть предположение, что класс Foo сопоставим на основе его уникального идентификатора и не всех данных в его содержимом:
Collection<Foo> oldSet = ...;
Collection<Foo> newSet = ...;
private Collection difference(Collection a, Collection b) {
Collection result = a.clone();
result.removeAll(b)
return result;
}
private Collection intersection(Collection a, Collection b) {
Collection result = a.clone();
result.retainAll(b)
return result;
}
public doWork() {
// if foo is in(*) oldSet but not newSet, call doRemove(foo)
Collection removed = difference(oldSet, newSet);
if (!removed.isEmpty()) {
loop removed {
Foo foo = removedIter.next();
doRemove(foo);
}
}
//else if foo is not in oldSet but in newSet, call doAdd(foo)
Collection added = difference(newSet, oldSet);
if (!added.isEmpty()) {
loop added {
Foo foo = addedIter.next();
doAdd(foo);
}
}
// else if foo is in both collections but modified, call doUpdate(oldFoo, newFoo)
Collection matched = intersection(oldSet, newSet);
Comparator comp = new Comparator() {
int compare(Object o1, Object o2) {
Foo f1, f2;
if (o1 instanceof Foo) f1 = (Foo)o1;
if (o2 instanceof Foo) f2 = (Foo)o2;
return f1.activated == f2.activated ? f1.startdate.compareTo(f2.startdate) == 0 ? ... : f1.startdate.compareTo(f2.startdate) : f1.activated ? 1 : 0;
}
boolean equals(Object o) {
// equal to this Comparator..not used
}
}
loop matched {
Foo foo = matchedIter.next();
Foo oldFoo = oldSet.get(foo);
Foo newFoo = newSet.get(foo);
if (comp.compareTo(oldFoo, newFoo ) != 0) {
doUpdate(oldFoo, newFoo);
} else {
//else if !foo.activated && foo.startDate >= now, call doStart(foo)
if (!foo.activated && foo.startDate >= now) doStart(foo);
// else if foo.activated && foo.endDate <= now, call doEnd(foo)
if (foo.activated && foo.endDate <= now) doEnd(foo);
}
}
}
Что касается ваших вопросов: Если я преобразую oldSet и newSet в HashMap (порядок здесь не имеет значения), с помощью ключей IDs, будет ли это облегчать чтение кода и его сравнение? Сколько времени & производительность памяти теряется при преобразовании? Я думаю, что вы, вероятно, сделаете код более читаемым, используя карту BUT...you, вероятно, потребуется больше памяти и времени во время преобразования.
Будет ли повторение двух наборов и выполнение соответствующей операции более эффективным и лаконичным? Да, это было бы лучшим из обоих миров, особенно если бы вы следовали совету @Mike Sharek о том, чтобы свернуть свой собственный список с помощью специализированных методов или следовать чему-то вроде Шаблона дизайна посетителя, чтобы запустить свою коллекцию и обработать каждый элемент.
Я бы перешел к спискам и решил это таким образом:
- Сортировка обоих списков по возрастанию идентификатора с помощью пользовательского компаратора , если объекты в списках не сопоставимы
- Перебирайте элементы в обоих списках, как на этапе слияния в алгоритме сортировки слиянием, но вместо слияния списков вы проверяете свою логику.
Код был бы более или менее похож на этот:
/* Main method */
private void execute(Collection<Foo> oldSet, Collection<Foo> newSet) {
List<Foo> oldList = asSortedList(oldSet);
List<Foo> newList = asSortedList(newSet);
int oldIndex = 0;
int newIndex = 0;
// Iterate over both collections but not always in the same pace
while( oldIndex < oldList.size()
&& newIndex < newIndex.size()) {
Foo oldObject = oldList.get(oldIndex);
Foo newObject = newList.get(newIndex);
// Your logic here
if(oldObject.getId() < newObject.getId()) {
doRemove(oldObject);
oldIndex++;
} else if( oldObject.getId() > newObject.getId() ) {
doAdd(newObject);
newIndex++;
} else if( oldObject.getId() == newObject.getId()
&& isModified(oldObject, newObject) ) {
doUpdate(oldObject, newObject);
oldIndex++;
newIndex++;
} else {
...
}
}// while
// Check if there are any objects left in *oldList* or *newList*
for(; oldIndex < oldList.size(); oldIndex++ ) {
doRemove( oldList.get(oldIndex) );
}// for( oldIndex )
for(; newIndex < newList.size(); newIndex++ ) {
doAdd( newList.get(newIndex) );
}// for( newIndex )
}// execute( oldSet, newSet )
/** Create sorted list from collection
If you actually perform any actions on input collections than you should
always return new instance of list to keep algorithm simple.
*/
private List<Foo> asSortedList(Collection<Foo> data) {
List<Foo> resultList;
if(data instanceof List) {
resultList = (List<Foo>)data;
} else {
resultList = new ArrayList<Foo>(data);
}
Collections.sort(resultList)
return resultList;
}