我有一个问题在python文档中并不是很清楚(https://docs.python.org/2/library/stdtypes.html#set.intersection)。
使用set.intersection时,结果集包含当前集或其他对象?如果两个对象具有相同的值但在内存中是不同的对象。
我使用它来比较先前从文件中提取的提取与来自互联网的新提取。两者都有一些类似的对象,但我想更新旧的。
或者可能有一个更简单的替代方案来实现这一目标?如果集合实现__getitem__
,那将会更容易。
oldApsExtract = set()
if (os.path.isfile("Apartments.json")):
with open('Apartments.json', mode='r') as f:
oldApsExtract = set(jsonpickle.decode(f.read()))
newApsExtract = set(getNewExtract())
updatedAps = oldApsExtract.intersection(newApsExtract)
deletedAps = oldApsExtract.difference(newApsExtract)
newAps = newApsExtract.difference(oldApsExtract)
for ap in deletedAps:
ap.mark_deleted()
for ap in updatedAps:
ap.update()
saveAps = list(oldApsExtract) + list(newAps)
with open('Apartments.json', mode='w') as f:
f.write(jsonpickle.encode(saveAps))
答案 0 :(得分:6)
如果集合与b中的交叉元素大小相同,则使用的对象会有所不同,如果b包含更多元素,则返回a中的对象:
i = "$foobar" * 100
j = "$foob" * 100
l = "$foobar" * 100
k = "$foob" * 100
print(id(i), id(j))
print(id(l), id(k))
a = {i, j}
b = {k, l, 3}
inter = a.intersection(b)
for ele in inter:
print(id(ele))
输出:
35510304 35432016
35459968 35454928
35510304
35432016
现在它们的大小相同:
i = "$foobar" * 100
j = "$foob" * 100
l = "$foobar" * 100
k = "$foob" * 100
print(id(i), id(j))
print(id(l), id(k))
a = {i, j}
b = {k, l}
inter = a.intersection(b)
for ele in inter:
print(id(ele))
输出:
35910288 35859984
35918160 35704816
35704816
35918160
source的相关部分。行if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so))
,n比较的结果似乎决定迭代哪个对象以及使用哪些对象。
if (PySet_GET_SIZE(other) > PySet_GET_SIZE(so)) {
tmp = (PyObject *)so;
so = (PySetObject *)other;
other = tmp;
}
while (set_next((PySetObject *)other, &pos, &entry)) {
key = entry->key;
hash = entry->hash;
rv = set_contains_entry(so, key, hash);
if (rv < 0) {
Py_DECREF(result);
return NULL;
}
if (rv) {
if (set_add_entry(result, key, hash)) {
Py_DECREF(result);
return NULL;
}
如果你传递的是一个非集合的对象,那么同样的情况则不然,并且长度与使用来自iterable的对象无关:
it = PyObject_GetIter(other);
if (it == NULL) {
Py_DECREF(result);
return NULL;
}
while ((key = PyIter_Next(it)) != NULL) {
hash = PyObject_Hash(key);
if (hash == -1)
goto error;
rv = set_contains_entry(so, key, hash);
if (rv < 0)
goto error;
if (rv) {
if (set_add_entry(result, key, hash))
goto error;
}
Py_DECREF(key);
当你传递一个iterable时,首先它可能是一个迭代器,所以你不能在不消耗的情况下检查大小,如果你传递了一个列表,那么查找将是0(n)
所以只需迭代迭代就可以了传入,相反,如果您有一组1000000
元素和一个10
元素,那么检查10
是否在1000000
中是否有意义是有意义的检查1000000
中是否有任何10
,因为查找平均应为0(1)
,这意味着线性传递超过10而线性传递超过1000000个元素。
如果您查看wiki.python.org/moin/TimeComplexity,则会进行备份:
平均情况 - &gt;交点s&amp; t O(min(len(s),len(t))
最坏情况 - &gt; O(len(s)* len(t))O(len(s)* len(t))
如果t不是 ,则将“min”替换为“max”
因此,当我们传递一个iterable时,我们应该始终从b:
获取对象i = "$foobar" * 100
j = "$foob" * 100
l = "$foobar" * 100
k = "$foob" * 100
print(id(i), id(j))
print(id(l), id(k))
a = {i, j}
b = [k, l, 1,2,3]
inter = a.intersection(b)
for ele in inter:
print(id(ele))
你从b获得对象:
20854128 20882896
20941072 20728768
20941072
20728768
如果你真的想要决定你保留哪些对象,那么就进行迭代并自己查找你想要的任何对象。
答案 1 :(得分:0)
你可以做的一件事是使用python词典。访问仍然是O(1),元素很容易访问,并且如下所示的简单循环可以获得交集功能:
res=[]
for item in dict1.keys():
if dict2.has_key(item):
res.append(item)
这里的优点是您可以完全控制正在发生的事情,并可以根据需要进行调整。例如,也可以执行以下操作:
if dict1.has_key(item):
dict1[item]=updatedValue