Python Set Intersection - 返回哪些对象

时间:2015-12-30 23:31:53

标签: python set

我有一个问题在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))

2 个答案:

答案 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