在特定情况下 Python 中的列表理解
List comprehension in Python under specific circumstances
lst_a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
lst_b = [[1, 4, 7], [6, 5, 4], [9, 8, 7]]
我的目标是检查 lst_a
中的所有嵌套列表,如果第一个条目 == lst_b
中任何元素的第一个条目。如果不是,则仅复制该子列表。在此示例中,他不会复制 lst_a[0]
,而是复制 1 和 2.
我试图通过列表理解来实现我的目标,但它行不通。
zero = [x[0] for x in lst_a]
if zero not in lst_b:
# I don't know what to do here.
创建元组或字典是不可能的,因为整个过程都在一个循环中,每秒钟都有新数据进来,我尽量避免将重复项复制到列表中。
编辑:lst_b
在整个过程之后应该看起来像这样:
lst_b = [[1, 4, 7], [6, 5, 4], [9, 8, 7], [4, 5, 6], [7, 8, 9]]
可能有更有效的方法来做到这一点,但这实现了目标。
>>> [a for a in lst_a if a[0] not in [b[0] for b in lst_b]]
[[4, 5, 6], [7, 8, 9]]
将 lst_b
中的所有第一个元素提取到一个集合中,以便您可以有效地检查成员资格。然后使用列表理解复制 lst_a
中符合您的条件的所有子列表。
first_elements = {x[0] for x in lst_b}
result = [x for x in lst_a if x[0] not in first_elements]
有点难吃,但还不错:
lst_b.extend(x for x in lst_a if not any(x[0] == y[0] for y in lst_b)
如果您想要一个 new 列表而不是修改 lst_b
,那么
lst_c = lst_b + [x for x in lst_a if not any(x[0] == y[0] for y in lst_b)]
无论哪种情况,我们都会检查 lst_a
中的每个子列表 x
。如果子列表的第一个元素等于 lst_b
中任何子列表的第一个元素,any(x[0] == y[0] for y in lst_b)
就是 True
。如果不是,那么我们将在最终结果中包含x
。
使用 any
可以让我们避免在 lst_b
中检查 每个 子列表,当找到单个匹配项就足够时。 (在某些情况下,这可能比首先创建一整套第一个元素更有效,如@barmar 的回答,但平均而言,这种方法可能更有效。)
另一种方式:
exclude=set(next(zip(*lst_b)))
lst_b+=[sl for sl in lst_a if sl[0] not in exclude]
>>> lst_b
[[1, 4, 7], [6, 5, 4], [9, 8, 7], [4, 5, 6], [7, 8, 9]]
解释:
zip(*lst_b)
是矩阵 lst_b
的逆矩阵的生成器,*
扩展了子列表,这创建了一个生成器,依次生成 [(1, 6, 9), (4, 5, 8), (7, 4, 7)]
。
next(zip(*lst_b)
我们只需要逆的第一个元素:(1,6,9)
set(next(zip(*lst_b)))
只需要那个的uniq元素就变成一个集合。你得到 {1, 6, 9}
(顺序无关紧要)
[sl for sl in lst_a if sl[0] not in exclude]
根据该条件过滤。
lst_b+=
用过滤后的元素扩展 lst_b
。
盈利!
lst_a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
lst_b = [[1, 4, 7], [6, 5, 4], [9, 8, 7]]
我的目标是检查 lst_a
中的所有嵌套列表,如果第一个条目 == lst_b
中任何元素的第一个条目。如果不是,则仅复制该子列表。在此示例中,他不会复制 lst_a[0]
,而是复制 1 和 2.
我试图通过列表理解来实现我的目标,但它行不通。
zero = [x[0] for x in lst_a]
if zero not in lst_b:
# I don't know what to do here.
创建元组或字典是不可能的,因为整个过程都在一个循环中,每秒钟都有新数据进来,我尽量避免将重复项复制到列表中。
编辑:lst_b
在整个过程之后应该看起来像这样:
lst_b = [[1, 4, 7], [6, 5, 4], [9, 8, 7], [4, 5, 6], [7, 8, 9]]
可能有更有效的方法来做到这一点,但这实现了目标。
>>> [a for a in lst_a if a[0] not in [b[0] for b in lst_b]]
[[4, 5, 6], [7, 8, 9]]
将 lst_b
中的所有第一个元素提取到一个集合中,以便您可以有效地检查成员资格。然后使用列表理解复制 lst_a
中符合您的条件的所有子列表。
first_elements = {x[0] for x in lst_b}
result = [x for x in lst_a if x[0] not in first_elements]
有点难吃,但还不错:
lst_b.extend(x for x in lst_a if not any(x[0] == y[0] for y in lst_b)
如果您想要一个 new 列表而不是修改 lst_b
,那么
lst_c = lst_b + [x for x in lst_a if not any(x[0] == y[0] for y in lst_b)]
无论哪种情况,我们都会检查 lst_a
中的每个子列表 x
。如果子列表的第一个元素等于 lst_b
中任何子列表的第一个元素,any(x[0] == y[0] for y in lst_b)
就是 True
。如果不是,那么我们将在最终结果中包含x
。
使用 any
可以让我们避免在 lst_b
中检查 每个 子列表,当找到单个匹配项就足够时。 (在某些情况下,这可能比首先创建一整套第一个元素更有效,如@barmar 的回答,但平均而言,这种方法可能更有效。)
另一种方式:
exclude=set(next(zip(*lst_b)))
lst_b+=[sl for sl in lst_a if sl[0] not in exclude]
>>> lst_b
[[1, 4, 7], [6, 5, 4], [9, 8, 7], [4, 5, 6], [7, 8, 9]]
解释:
zip(*lst_b)
是矩阵lst_b
的逆矩阵的生成器,*
扩展了子列表,这创建了一个生成器,依次生成[(1, 6, 9), (4, 5, 8), (7, 4, 7)]
。next(zip(*lst_b)
我们只需要逆的第一个元素:(1,6,9)
set(next(zip(*lst_b)))
只需要那个的uniq元素就变成一个集合。你得到{1, 6, 9}
(顺序无关紧要)[sl for sl in lst_a if sl[0] not in exclude]
根据该条件过滤。lst_b+=
用过滤后的元素扩展lst_b
。
盈利!