我有两个清单,
l1 = [1,2,3,4,5,6]
l2 = [3,2]
我想要的是删除l2中列表l1的元素,因为我做了类似的事情,
for x in l1:
if x in l2:
l1.remove(x)
它提供类似
的输出[1, 3, 4, 5, 6]
但输出应该像
[1, 4, 5, 6]
任何人都可以阐明这一点。
答案 0 :(得分:9)
这很容易解释。
考虑你拥有的第一个数组:
| 1 | 2 | 3 | 4 | 5 | 6 |
现在开始迭代
| 1 | 2 | 3 | 4 | 5 | 6 |
^
没有任何反应,迭代器递增
| 1 | 2 | 3 | 4 | 5 | 6 |
^
2被删除
| 1 | 3 | 4 | 5 | 6 |
^
迭代器增量
| 1 | 3 | 4 | 5 | 6 |
^
瞧,3还在那里。
解决方案是迭代载体的副本,例如
for x in l1[:]: <- slice on entire array
if x in l2:
l1.remove(x)
或反向迭代:
for x in reversed(l1):
if x in l2:
l1.remove(x)
其行为如下:
| 1 | 2 | 3 | 4 | 5 | 6 |
^
| 1 | 2 | 3 | 4 | 5 | 6 |
^
| 1 | 2 | 4 | 5 | 6 |
^
| 1 | 2 | 4 | 5 | 6 |
^
| 1 | 4 | 5 | 6 |
^
| 1 | 4 | 5 | 6 |
^
答案 1 :(得分:7)
为什么不让它变得更简单?如果我们只想删除l1
中的元素,则无需实际迭代l2
:
for item in l2:
while item in l1:
l1.remove(item)
这为您提供了所需的输出......
此外,正如评论者指出的那样,如果我们有可能有重复项:
l1 = filter(lambda x: x not in l2, l1)
..或使用列表推导的许多其他变体。
答案 2 :(得分:3)
您希望外部循环读取:
for x in l1[:]:
...
您无法在迭代时更改列表并期望获得合理的结果。上面的技巧使得l1
的副本并在副本上进行迭代。
请注意,如果输出列表中的顺序无关紧要,并且您的元素是唯一且可清除的,则可以使用集合:
set(l1).difference(l2)
将为您提供一个输出集,但您可以轻松地从中构建一个列表:
l1 = list(set(l1).difference(l2))
答案 3 :(得分:2)
正如其他人所说的那样,在循环播放列表时无法编辑列表。这里一个好的选择是使用a list comprehension创建一个新列表。
removals = set(l2)
l1 = [item for item in l1 if item not in removals]
我们设置一个集合作为一个集合的成员资格检查明显快于列表。
答案 4 :(得分:2)
如果l1中的重复顺序和丢失无关紧要:
list(set(l1) - set(l2))
只有在需要结果作为列表时才需要最后一个列表()。您也可以使用结果集,它也是可迭代的。 如果您需要它,您当然可以在结果列表中调用l.sort()。
答案 5 :(得分:1)
修改:删除了我的原始答案,因为即使它确实给出了正确的结果,但出于非直观原因这样做了,并且也不是很快......所以我刚刚离开时间安排:
import timeit
setup = """l1 = list(range(20)) + list(range(20))
l2 = [2, 3]"""
stmts = {
"mgilson": """for x in l1[:]:
if x in l2:
l1.remove(x)""",
"petr": """for item in l2:
while item in l1:
l1.remove(item)""",
"Lattyware": """removals = set(l2)
l1 = [item for item in l1 if item not in removals]""",
"millimoose": """for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass""",
"Latty_mgilson": """removals = set(l2)
l1[:] = (item for item in l1 if item not in removals)""",
"mgilson_set": """l1 = list(set(l1).difference(l2))"""
}
for idea in stmts:
print("{0}: {1}".format(idea, timeit.timeit(setup=setup, stmt=stmts[idea])))
结果(Python 3.3.0 64bit,Win7):
mgilson_set: 2.5841989922197333
mgilson: 3.7747968857414813
petr: 1.9669433777815701
Latty_mgilson: 7.262900152285258
millimoose: 3.1890831105541793
Lattyware: 4.573971325181478
答案 6 :(得分:0)
当你在迭代它时修改列表l1
,这将导致奇怪的行为。 (迭代期间将跳过3
。)
迭代副本,或更改算法以迭代l2
而不是:
for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass
(这应该比明确地测试不,这会在if x in l1
更好。)l1
增长时表现得非常糟糕。
答案 7 :(得分:0)
FWIW我得到的结果明显不同于@Tim Pietzcker使用我认为更真实的输入数据集并使用更严格(但其他方面相同)的方法来计算不同人的答案。
名称和代码片段与Tim相同,只是我添加了名为Lattyware
的名为Lattyware_rev
的变体,它确定要保留哪些元素而不是拒绝 - 它已转比前者慢。 请注意,最快的两个不保留l1
的顺序。
这是最新的时间码:
import timeit
setup = """
import random
random.seed(42) # initialize to constant to get same test values
l1 = [random.randrange(100) for _ in xrange(100)]
l2 = [random.randrange(100) for _ in xrange(10)]
"""
stmts = {
"Minion91": """
for x in reversed(l1):
if x in l2:
l1.remove(x)
""",
"mgilson": """
for x in l1[:]: # correction
if x in l2:
l1.remove(x)
""",
"mgilson_set": """
l1 = list(set(l1).difference(l2))
""",
"Lattyware": """
removals = set(l2)
l1 = [item for item in l1 if item not in removals]
""",
"Lattyware_rev": """
keep = set(l1).difference(l2)
l1 = [item for item in l1 if item in keep]
""",
"Latty_mgilson": """
removals = set(l2)
l1[:] = (item for item in l1 if item not in removals)""",
"petr": """
for item in l2:
while item in l1:
l1.remove(item)
""",
"petr (handles dups)": """
l1 = filter(lambda x: x not in l2, l1)
""",
"millimoose": """
for x in l2:
try:
while True: l1.remove(x)
except ValueError: pass
""",
"K.-Michael Aye": """
l1 = list(set(l1) - set(l2))
""",
}
N = 10000
R = 3
timings = [(idea,
min(timeit.repeat(stmts[idea], setup=setup, repeat=R, number=N)),
) for idea in stmts]
longest = max(len(t[0]) for t in timings) # length of longest name
exec(setup) # get an l1 & l2 just for heading length measurements
print('fastest to slowest timings of ideas:\n' +\
' ({:,d} timeit calls, best of {:d} executions)\n'.format(N, R)+\
' len(l1): {:,d}, len(l2): {:,d})\n'.format(len(l1), len(l2)))
for i in sorted(timings, key=lambda x: x[1]): # sort by speed (fastest first)
print "{:>{width}}: {}".format(*i, width=longest)
输出:
fastest to slowest timings of ideas:
(10,000 timeit calls, best of 3 executions)
len(l1): 100, len(l2): 10)
mgilson_set: 0.143126456832
K.-Michael Aye: 0.213544010551
Lattyware: 0.23666971551
Lattyware_rev: 0.466918513924
Latty_mgilson: 0.547516608553
petr: 0.552547776807
mgilson: 0.614238139366
Minion91: 0.728920176815
millimoose: 0.883061820848
petr (handles dups): 0.984093136969
当然,请告诉我是否有一些根本错误的东西可以解释截然不同的结果。
答案 8 :(得分:0)
l1 = [1, 2, 3, 4, 5, 6]
l2 = [3, 2]
[l1.remove(x) for x in l2]
print l1
[1, 4, 5, 6]