Проверьте, есть ли элемент в списке со ссылочным равенством - PullRequest
1 голос
/ 11 апреля 2020

Я хочу проверить, есть ли элемент в списке со ссылочным равенством, а не со структурным равенством.

Для ясности:

ссылочное равенство между двумя элементами проверяется с помощью item1 is item2

структурное равенство проверяется с помощью item1 == item2

Структурное равенство для проверки, если элемент уже есть в списке, легко сделать так:

item in list

Итак, я ищу эквивалентную строку со ссылочным равенством. Возможно ли это без зацикливания каждого элемента в списке?

Пример того, как это нужно реализовать (просто для пояснения):

def get_all_items_in_list(items):
   all_items = []
   for item in items:
       if not item in all_items:   # replace with referential equality here
           all_items.append(item)
   return all_items

# setup
a = (1, [])
b = (1, [])
print(a is b)    # prints False
items = [a, a, b]
print(get_all_items_in_list(items))  # should print [(1, []), (1, [])] but prints [(1, [])]

Ответы [ 5 ]

2 голосов
/ 13 апреля 2020

Вы не сможете сделать это без некоторого вида l oop. В python из in нет эквивалентного оператора, который проверяет идентичность. Краткое решение может выглядеть следующим образом:

l = [1,2,3]
l2 = [[1, 2, 3], [4, 5, 6]]
l3 = [[1, 2, 3], [4, 5, 6], l]

any(l is sub for sub in l2)
# false

any(l is sub for sub in l3)
# True

Это все еще циклы, но он выйдет рано, если будет найдено истинное значение.

Если вам действительно нужно используйте оператор для этого, вы можете создать подкласс UserList и переопределить __contains__(). Это изменит поведение in:

from collections import UserList

class identList(UserList):
    def __contains__(self, other):
        return any(other is sub for sub in self)


l = [1,2,3]
l2 = identList([[1, 2, 3], [4, 5, 6]])
l3 = identList([[1, 2, 3], [4, 5, 6], l])

l in l2
# False

l in l3
# True
1 голос
/ 20 апреля 2020
#With minimal changes in existing code snippet
def get_all_items_in_list(items):
   all_items = {}
   for item in items:
       if not id(item) in all_items:   # replace with referential equality here
           all_items[id(item)] = item
   return all_items.values()

# setup
a = (1, [])
b = (1, [])
print(a is b)    # prints False
items = [a, a, b]
print(get_all_items_in_list(items))

Выход:

False

dict_values([(1, []), (1, [])])
1 голос
/ 13 апреля 2020

Таким образом, в соответствии с оператором is "python * , он проверяет объекты identity, что может быть достигнуто с помощью функции id() ( прокрутите дальше для поиска решения *) 1006 *).

# as you did
a = (1, [])
b = (1, []) # two different objects
print(a is b)
print(id(a), id(b))
>>> False
>>> 2076884715144 2076884729224

# Now let's try making the second object the same
c = (2, [])
d = c #objects are the same
print(c is d)
print(id(c), id(d))
>>> True
>>> 2076899815240 2076899815240

РЕШЕНИЕ:

Идея ниже - получить все идентификаторы () в другом списке с той же позицией, что и исходный список. Проверяя, есть ли элемент в списке, вы проверяете, есть ли идентификация.

def get_ids_items_in_list(items):
    """ Get the identity of the objects in same order as list"""
    items_ids = []
    for item in items:
        items_ids.append(id(item))
    return items_ids

def get_all_items_in_list(items_list):
    # get our ids
    items_ids = get_ids_items_in_list(items_list)

    all_items = []
    all_items_id = []

    # Loops over the ids but using enumerate to get positions
    for idx, item in enumerate(items_ids):
        if not item in all_items_id:
            all_items_id.append(item)
            # if id is in list, append object according to position
            all_items.append(items_list[idx])
    return all_items

# setup
a = (1, [])
b = (1, [])
print(a is b)    # prints False

items = [a, a, b]
print(get_all_items_in_list(items))

>>> False
>>> [(1, []), (1, [])]

БОЛЬШЕ В ПРЕДМЕТЕ:

# another thing to notice is that a simple copy()
# will return the same object
from copy import copy
e = (3, [])
f = copy(e)
print(e is f)
print(id(e), id(f))
>>> True
>>> 2076884710600 2076884710600

# but a deepcopy will change the identity
from copy import deepcopy
g = (4, [])
h = deepcopy(g)
print(g is h)
print(id(g), id(h))
>>> False
>>> 2076884714120 2076884715016
1 голос
/ 13 апреля 2020

Вы можете использовать промежуточное значение dict, обозначенное элементом id, в качестве набора идентификаторов:

def get_all_items_in_list(items):
   return {id(it): it for it in items}.values()

# arrange
a = (1, [])
b = (1, [])
items = [a, a, b]

# act
result = list(get_all_items_in_list(items))

# assert
print(result[0] is a)
print(result[1] is b)
0 голосов
/ 11 апреля 2020

Попробуйте,

a=10
b=20
c=30
l=[id(a),id(b),id(c)]
id(a) in l
...