如何确定两个元素是否属于同一个列表

时间:2017-11-21 15:37:32

标签: python python-3.x

我有几个列表,每个列表包含几个城市。我需要检查任何两个随机元素是否属于同一个列表。

简单示例:

list1 = ['London', 'Manchester', 'Liverpool', 'Edimburgh']
list2 = ['Dublin', 'Cork', 'Galway']
list3 = ['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon', ...]
list4 = ['Washington', 'New York', 'San Francisco', 'LA', 'Boston', ...]

预期结果:

> in_same_group('London', 'Liverpool')
> True
>
> in_same_group('Berlin', 'Washington')
> False

该功能经常被调用,因此速度至关重要。最大的列表最多可包含1000个元素。

最有效的方法是什么?

这是我到目前为止所尝试的,但它太慢了:

def in_same_group(city1, city2):

    same_group = False
    for this_list in [list1, list2, list3...]:
        if city1 in this_list and city2 in this_list:
            return True

    return same_group

8 个答案:

答案 0 :(得分:21)

指数集的字典

这里是Horia的proposal和我原来的混合物。您可以将城市定义为dict作为键,将索引集定义为值:

list1 = ['London', 'Manchester', 'Liverpool', 'Edimburgh']
list2 = ['Dublin', 'Cork', 'Galway', 'Paris', 'Rome']
list3 = ['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon'] 
list4 = ['Washington', 'New York', 'San Francisco', 'LA', 'Boston']
# Note that 'Paris' and 'Rome' are both in list2 and list3

groups = [list1, list2, list3, list4]

indices = {}

for i, group in enumerate(groups):
    for city in group:
        indices.setdefault(city, set()).add(i)

结构紧凑,看起来像这样:

print(indices)
#{'London': {0}, 'Manchester': {0}, 'Liverpool': {0}, 'Edimburgh': {0}, 'Dublin': {1}, 'Cork': {1}, 'Galway': {1}, 'Paris': {1, 2}, 'Rome': {1, 2}, 'Berlin': {2}, 'Munich': {2}, 'Frankfurt': {2}, 'Milan': {2}, 'Madrid': {2}, 'Barcelona': {2}, 'Lisbon': {2}, 'Washington': {3}, 'New York': {3}, 'San Francisco': {3}, 'LA': {3}, 'Boston': {3}}

对于任何城市对,您都可以通过set intersection得到一组常见索引:

def common_groups(city1, city2):
    return indices.get(city1, set()) & indices.get(city2, set())

print(common_groups('London', 'Liverpool'))
#  {0}
print(common_groups('London', 'Paris'))
#  set()
print(common_groups('Cork', 'Paris'))
# {1}
print(common_groups('Rome', 'Paris'))
# {1, 2}
print(common_groups('Rome', 'Nowhere'))
# set()

Python中的空集是假的。

对于n个城市,创建字典将为O(n),空间要求应为O(n),查找效果为O(1)。作为奖励,查询不会返回布尔值,而是返回一组索引。

最后,由于设置了交叉点,如果您想检查三个或更多城市是否在同一组中,此方法也可以使用。

答案 1 :(得分:8)

一种方法是建立从城市到其组号的地图。所以你要构建类似的东西:

mapping = {
    'London': 1,
    ...,
    'Berlin': 3
    ...
}

然后您的in_same_group功能可以是:

def in_same_group(item1, item2):
    gr1 = mapping[item1]
    gr2 = mapping[item2]
    return gr1 == gr2

就速度而言,这是非常快的,因为它只是两个字典查找,在Python和一个比较中非常快,这又是非常快的。在大哦,函数是O(1)

但它假设元素只是一个组的一部分。在您提供的示例中似乎就是这种情况。

必须花费额外的时间和内存来实际构建地图。但它会在对in_same_group的所有电话中摊销。 OTOH,无论你的方法如何,你都可能无法建立索引结构。

构建映射的代码是:

def build_mapping(groups):
    mapping = {}
    for i in range(0, len(groups)):
        for g in groups[i]:
            mapping[g] = i
    return mapping

这不是最漂亮的代码,但它完成了工作。

答案 2 :(得分:5)

首先,使用集合,而不是列表(并使用集合列表而不是单独的变量)。

master_list = []
master_list.append(set(['London', 'Manchester', 'Liverpool', 'Edimburgh']))
master_list.append(set(['Dublin', 'Cork', 'Galway']))
master_list.append(set(['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon', ...]))
master_list.append(set(['Washington', 'New York', 'San Francisco', 'LA', 'Boston', ...]))

(根据您的使用情况,具有更有意义的键的dict可能比列表更合适。)

其次,构建一个将每个元素映射到其集合的字典:

# E.g., index['London'] == set(['London', 'Manchester', ...])
index = dict((item, s) for s in master_list for item in s)

现在,您只需检查两个项目是否属于同一组。

def in_same_group(i1, i2):
    return index[i1] is index[i2]

答案 3 :(得分:2)

您可以遍历列表并确定是否在其中找到了两个搜索查询。然后,返回新形成的列表的布尔值。

def search(s1, s2):
   list1 = ['London', 'Manchester', 'Liverpool', 'Edimburgh']
   list2 = ['Dublin', 'Cork', 'Galway']
   list3 = ['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon']
   list4 = ['Washington', 'New York', 'San Francisco', 'LA', 'Boston']
   return bool([i for i in [list1, list2, list3, list4] if s1 in i and s2 in i])

答案 4 :(得分:1)

如果你希望它真的很快,你应该改变你的数据结构,以获得一个集合字典,其中密钥将是一个城镇,集合将包含同一组中的所有城镇。这样您就可以确保in_same_group只需要:

  • 一个字典研究
  • 关于单一收容研究

由于这些访问针对词典和集合进行了优化,因此研究应尽可能快地进行

代码可以是:

import collections

h = collections.defaultdict(set)

lists = [list1, list2, list3, list4]
for l in lists:
    for town in l:
        for other in l:
            if town != other:
                h[town].add(other)

该功能现在非常简单:

def in_same_group(t1, t2):
    return t2 in h[t1]

答案 5 :(得分:0)

您好,您可以尝试使用Pandas

import pandas as pd


list1 = ['London', 'Manchester', 'Liverpool', 'Edimburgh']

list2 = ['Dublin', 'Cork', 'Galway']

list3 = ['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon']

list4 = ['Washington', 'New York', 'San Francisco', 'LA', 'Boston']


----------


a = pd.Series(list(list1))

b = pd.Series(list(list2))

c = pd.Series(list(list3))

d = pd.Series(list(list4))

lists = [a,b,c,d]


----------


for i in lists:

    if (i.isin(['London']).any()) and (i.isin(['Manchester']).any()) == True:
        print('Same Group')
    else:
        print('Different Group')

结果

相同组

不同的小组

不同的小组

不同的小组

答案 6 :(得分:0)

在对提案进行了一些速度测试之后,我意识到关于所提出的解决方案的一个弱点,如果我没有弄错的话,那就是完整的循环将始终用于映射。通过先前跳过循环以防结果已知,可以提高速度。

此外,如果一个列表比其他列表大得多,则有可能加快速度。

我认为以下内容可能更快,以防其中一个列表比其他列表大得多。假设list3比其他的大得多。

list1 = ['London', 'Manchester', 'Liverpool', 'Edimburgh']
list2 = ['Dublin', 'Cork', 'Galway']
list3 = ['Berlin', 'Munich', 'Frankfurt', 'Paris', 'Milan', 'Rome', 'Madrid', 'Barcelona', 'Lisbon', ...] #assuming list3 is much larger than all others
list4 = ['Washington', 'New York', 'San Francisco', 'LA', 'Boston', ...]

可能性是:

def in_same_group(city1, city2):

    for group in [list1, list2, list4]: #note that list3, the largest, is skipped
            if city1 in group and city2 not in group:
                return False

    return True #if this point is reached, both cities belong to the biggest group

答案 7 :(得分:0)

在数据库术语中,您具有一对多的关系。一个列表可以包含许多名称,但每个名称只能出现在一个列表中。

试试这个:

In [20]: city_lists = {city_name:list1 for city_name in list1}
In [21]: city_lists.update({city_name:list2 for city_name in list2})
In [22]: city_lists
Out[22]: 
{'Cork': ['Dublin', 'Cork', 'Galway'],
 'Dublin': ['Dublin', 'Cork', 'Galway'],
 'Edimburgh': ['London', 'Manchester', 'Liverpool', 'Edimburgh'],
 'Galway': ['Dublin', 'Cork', 'Galway'],
 'Liverpool': ['London', 'Manchester', 'Liverpool', 'Edimburgh'],
 'London': ['London', 'Manchester', 'Liverpool', 'Edimburgh'],
 'Manchester': ['London', 'Manchester', 'Liverpool', 'Edimburgh']}
In [23]: city_lists['Cork'] is city_lists['Dublin']
Out[23]: True
In [24]: city_lists['Cork'] is city_lists['London']
Out[24]: False

这非常有效。如果使用http://pythontutor.com可视化代码,您将看到dict包含对原始列表的引用,但不会复制列表本身。