Python Set Intersection - 返回哪些对象

标签 python set

我有一个问题在 python 文档中不是很清楚 (https://docs.python.org/2/library/stdtypes.html#set.intersection)。

当使用 set.intersection 时,结果集包含来自当前集或其他集的对象?如果两个对象具有相同的值但在内存中是不同的对象。

我正在使用它来比较以前从文件中提取的内容和来自互联网的新内容。两者都有一些相似的对象,但我想更新旧的。 或者也许有更简单的替代方法来实现这一目标?如果 sets 实现了 __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))

最佳答案

使用的对象各不相同,如果集合与 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;
            }

如果您传递的对象不是集合,则情况并非如此,并且长度与使用可迭代对象中的对象无关:

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);

当你传递一个可迭代对象时,首先它可能是一个迭代器,所以你不能在不消耗的情况下检查大小,如果你传递一个列表,那么查找将是 0(n) 所以它是有意义的只是迭代传入的可迭代对象,相比之下,如果您有一组 1000000 元素和一个带有 10 的元素,则检查 101000000 集合中,而不是检查 1000000 是否在你的 10 集合中,因为查找应该是 0(1) 平均,所以这意味着超过 10 个元素的线性传递与超过 1000000 个元素的线性传递。

如果您查看 wiki.python.org/moin/TimeComplexity ,这是备份的:

Average case -> Intersection s&t O(min(len(s), len(t))

Worst case -> O(len(s) * len(t))O(len(s) * len(t))

replace "min" with "max" if t is not a set

所以当我们传递一个可迭代对象时,我们应该总是从 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

如果您真的想决定保留哪些对象,请自己进行迭代和查找,保留您想要的任何对象。

关于Python Set Intersection - 返回哪些对象,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34538890/

相关文章:

python - python中的平面文件键值存储

python - 从 url 下载 .html 文件时出现超时错误

python - 获取图像的焦点像素

python celery 不工作

javascript - 将 javascript 集转换为字符串的最有效方法

python - 在pygame中射击子弹

c++ - std::includes in c++ 算法的复杂性

python - 带迭代的二维字典

Java 从集合中删除会导致 IllegalStateException

set - := mean when used in pseudocode? 是什么意思