Обратите внимание, что есть случаи, когда вы определили свой собственный пользовательский класс и хотите сохранить атрибуты, тогда вы должны использовать copy.copy()
или copy.deepcopy()
, а не альтернативы, например, в Python 3:
import copy
class MyList(list):
pass
lst = MyList([1,2,3])
lst.name = 'custom list'
d = {
'original': lst,
'slicecopy' : lst[:],
'lstcopy' : lst.copy(),
'copycopy': copy.copy(lst),
'deepcopy': copy.deepcopy(lst)
}
for k,v in d.items():
print('lst: {}'.format(k), end=', ')
try:
name = v.name
except AttributeError:
name = 'NA'
print('name: {}'.format(name))
Выходы:
lst: original, name: custom list
lst: slicecopy, name: NA
lst: lstcopy, name: NA
lst: copycopy, name: custom list
lst: deepcopy, name: custom list
Вы пытаетесь сделать то, что Java на самом деле не предназначено для.
Если вы в состоянии это сделать, вам лучше добавить атрибут к Object1
, который будет списком из Object2
, содержащего объекты, связанные с this
.
Если вы не можете, у нас еще есть возможность сделать это наивно, иначе вы можете попробовать что-то вроде этого:
HashSet<Integer> hs = new HashSet<Integer>(list2.size());
for(Object2 o : list2) {
hs.add(o.object1id);
}
//hs contains all the ids of list2
List<Object1> result = new ArrayList<Object1>(); //Or another class implementing List
for(Object1 o : list1) {
if(hs.contains(o.id))
result.add(o);
}
Не красиво, поскольку вам нужно сохранить все идентификаторы в HashSet, но так как добавление и доступ к элементам в HashSet - это O (1) (теоретически), алгоритм O (n + m)
Если ваш Object3
класс построен с помощью Object1
и Object2
, используйте HasMap
вместо HashSet
, где ключи являются идентификаторами, а значения - объектом2. Последний цикл for
в коде будет выглядеть следующим образом:
Object2 o2 = hs.get(o.id);
if(o2 != null)
result.add(new Object3(o, o2);
В дополнение к комментарию Óscar López:
Если ваш objectid1 не уникален, вам необходимо адаптировать код следующим образом:
HashMap<Integer, List<Object2>> hm = new HashMap<Integer, List<Object2>>();
for(Object2 o : list2) {
List<Object2> l = hm.get(o.objectid1);
if(l != null) {
l.add(o);
} else {
List<Object2> l = new ArrayList<Object2>();
l.add(o);
hm.put(o.objectid1, l);
}
//hm is map, where each entry contains the list of Object2 associated with objectid1
List<Object1> result = new ArrayList<Object1>();
for(Object1 o : list1) {
List<Object2> l = hm.get(o.id);
//l contains all Object2 with object1id = o.id
for(Object2 o2 : l)
result.add(new Object3(o, o2));
}
Все еще в O (n + m), но с большими константами ...
Я считаю, что решение O(n*m)
неизбежно, , если не создана более сложная инфраструктура структуры данных - эффективные объединения в базе данных реализованы с использованием индексов, хэшей и т. д. Также следует иметь в виду, что правильная реализация должна учитывать случай, когда более одного объекта в list2
имеет тот же object1id
- мой код работает в этом случае, но все решения, которые просто добавляют obj2.object1id
к Set
или как клавиши в Map
, не удастся.
Но стоит ли это сложность реализации? если входные списки малы, O(n*m)
решение будет работать нормально. Вот мое предложение, используя старые добрые вложенные циклы:
List<Object3> list3 = new ArrayList<>();
for (Object1 obj1 : list1) {
boolean found = false;
for (Object2 obj2 : list2) {
if (obj1.id.equals(obj2.object1id)) {
list3.add(new Object3(obj1, obj2));
found = true;
}
}
if (!found)
list3.add(new Object3(obj1, null));
}
Для работы выше, я использую выходной объект, который выглядит так:
public class Object3 {
private Object1 obj1;
private Object2 obj2;
public Object3(Object1 obj1, Object2 obj2) {
this.obj1 = obj1;
this.obj2 = obj2;
}
}
list2
имеется более одного объекта с таким же object1id
, очень вероятным сценарием в реальной базе данных.
– Óscar López
31 August 2014 в 17:25
n
строк, и вам нужно выполнить линейный поиск m
, чтобы найти все совпадения. Предотвращение этого - это то, почему базы данных индексы (или хэш Java) были созданы. Кроме того, ОП должен решить, что такое достаточно быстро. Не все должно быть оптимально быстрым.
– Tony Ennis
31 August 2014 в 17:47
Создайте индекс в списке. Сканировать список и заполнить индекс:
HashMap<Integer, Object2> index=HashMap<Integer, Object2>();
for (Object2 obj2: list2) {
index.put(obj2.object1id, obj2);
}
Затем сканируйте список и выполните соединение:
for (Object1 obj1: list1) {
Object2 obj2=index.get(obj1.id); // may be null
Object3 obj3=new Object3(obj1, obj2);
}
list2
имеют одинаковые object1id
.
– Óscar López
31 August 2014 в 17:21
Если вы используете Java 8, вы можете использовать потоки . Это может выглядеть примерно так (предполагая, что id
является идентификатором Object1 для поиска):
List<Object3> newList = obj2List.stream().filter(x -> x.object1id == id).map(x -> obj2To3(x)).collect(Collectors.toList());
Приведенный случай довольно расплывчатый, поэтому трудно дать более подробный ответ.
При условии, что они реализуют некоторый общий интерфейс (это облегчит задачу, особенно при кастинге), тогда это относительно просто.
Он все еще O (nm), так как вам нужно пройти оба длины списка, чтобы найти элементы для добавления.
public interface JoinInterface {
int getId();
int getObject1Id(); // likely baggage here
}
public static List<? extends JoinableEntity> leftJoin(List<? extends JoinableEntity> left,
List<? extends JoinableEntity> right) {
List<JoinableEntity> result = new ArrayList<>();
result.addAll(left);
for(JoinableEntity aLeft : left) {
for(JoinableEntity aRight : right) {
if(aLeft.getId() == aRight.getObject1Id()) {
result.add(aRight);
break;
}
}
}
return result;
}
Хорошим решением может быть преобразование списка объектов2 в карту. Затем перейдите в список Object1 и получите Object2 из Map, в конечном итоге создайте результат объединения и добавления в Object3 List.
list2
имеют одинаковыеobject1id
. – Óscar López 31 August 2014 в 17:22