在列表列表中查找重复元素

Find duplicate element in a list of lists

我正在寻找 Python 解决以下问题的想法。

给定列表列表...

[[20, 21, 22], [17, 18, 19, 20], [10, 11, 12, 13]]

如果任何或所有列表之间存在共同的重复元素,return 正确。如果所有元素都是唯一的,return False。

在上面的示例中,20 是常见的并且 return 为真。下面的示例将 return 错误,因为列表之间的所有数字都是唯一的。

[[20, 21, 22], [17, 18, 19], [10, 11, 12, 13]]

最后,不需要测试单个列表中的重复项,因为数字始终是连续的。

仅供参考 - 此问题将用于优化航空公司机组成员的月度计划。每个列表代表不能重叠的 3、4 或 5 天的航空旅行。

顺便说一句 - 这个问题不是一项任务,而是个人寻求减少工作并获得更多报酬的问题:)抱歉,我不清楚。我尝试了一种有效的蛮力方法,但希望有一种更优雅的 Pythonic 方法。我感谢所有回复,因为它们将我带入了 Python 编程的新领域。

假设您正在寻找具体目标(您的问题不清楚):

def find_dupe(lists, target):
    seen = set()
    for lst in lists:
        for item in lst:
            if item == target and item in seen:
                return True
            seen.add(item)

演示:

>>> find_dupe([[20, 21, 22], [17, 18, 19, 20], [10, 11, 12, 13]],
              20)
True

如果你不是,那么你可以简单地删除 item == target 条件

def find_dupe(lists):
    seen = set()
    for lst in lists:
        for item in lst:
            if item in seen:
                yield item
            seen.add(item)
num = Counter(i for j in alist for i in j) # flatten list into a single dimension
dup = [k for k, v in num.items() if v > 1] # checks the dict for duplicate values

如果您愿意放弃列表理解的优雅,您可以执行以下操作:

seen, dups = set(), set()
for l in ll:
    dups = dups.union(seen.intersection(set(l)))
    seen = seen.union(set(l))

你的答案应该在 dups.

编辑

正如下面 Steven Rumbalski 所指出的,set 成员操作参数中的 set 是多余的(而且不必要地昂贵)。

>>> from collections import Counter
>>> list_of_list = [[20, 21, 22], [17, 18, 19, 20], [10, 11, 12, 13]]
>>> counts = Counter(item for sublist in list_of_list for item in sublist)
>>> repeated_items = [item for item, count in counts.items() if count > 1]
>>> repeated_items
[20]

像这样:

l = [[20, 21, 22], [17, 18, 19, 20], [10, 11, 12, 13]]
dupes = []
flat = [item for sublist in l for item in sublist]
for f in flat:
    if flat.count(f) > 1:
        if f not in dupes:
            dupes.append(f)

if dupes:
    return True
else:
    return False

我建议你试试这个:

def find_dup(listOfLists):
   for index in range(len(listOfLists) - 1)
      result = [filter(lambda x: x in listOfLists[index], otherLists) for otherLists in listOfLists[index+1:]]
      if result:
          return True
   return False

想法是查看第一个列表 (listOfLists[0]) 并检查它的任何元素是否在其他列表 (listOfLists[1:]) 中重复,在肯定的情况下 return确实,在否定的情况下,查看第二个列表 (listOfLists[1]),然后再次查看其他列表 (listOfLists[2:]),依此类推。重要的是要避免从一开始就每次都检查。

我无法测试这个示例,但我认为它应该可以工作:)。

希望对您有所帮助。

此处以效率为目标。

def duplicates_exist(ll):
    seen = set()
    see = seen.add
    for l in ll:
        for element in set(l):
            if element in seen:
                return True
            see(element)
    return False

让我意识到我之前有一个不必要的生成器。 >_<

>>> seen = set()
>>> any(element in seen or seen.add(element)
        for lst in lists for element in set(lst))
True

我只使用 set(lst) 而不是 lst 因为不清楚子列表是否可以包含重复项。

正如@Shashank 所暗示的那样,这是有效的,因为它在第一个找到重复项时停止(就像 )。如果有很多子列表,但前两个有重复的,那么剩下的根本就不会看。因此,它比首先从各处收集所有重复项然后再将其转换为布尔值的解决方案更快。

更新: @abarnert 的评论让我想到了这个:

>>> max(Counter(chain.from_iterable(ll)).values()) > 1
True

或更短(但更慢):

>>> max(Counter(sum(lists, [])).values()) > 1
True

这两个不处理单个子列表中的重复项,但我发现假设这不会发生是合理的,否则规范应该真的这么说,或者至少示例应该有一个。