【发布时间】:2018-06-09 15:54:36
【问题描述】:
当我尝试在迭代其元素时更新集合时,它的行为应该是什么?
我在各种场景中进行了尝试,它不会对迭代开始后添加的元素进行迭代,也不会对迭代期间删除的元素进行迭代。如果我在迭代期间删除并放回任何元素,则正在考虑该元素。确切的行为是什么以及它是如何工作的?
这会打印字符串的所有排列:
def permutations(s):
ans = []
def helper(created, remaining):
if len(created) == len(s):
ans.append(''.join(created))
return
for ch in remaining:
remaining.remove(ch)
created.append(ch)
helper(created, remaining)
remaining.add(ch)
created.pop()
helper([], set(s))
return ans
这里的行为是不可预测的,有时会打印e,而有时却不会:
ab = set(['b','c','d'])
x = True
for ch in ab:
if x:
ab.remove('c')
ab.add('e')
x = False
print(ch)
在这里我总是只看到一次'c'。即使第一个字符是'c':
ab = set(['b','c','d'])
x = True
for ch in ab:
if x:
ab.remove('c')
ab.add('c')
x = False
print(ch)
以及实现上述功能相同目标的另一种方法:
def permwdups(s):
ans = []
def helper(created, remaining):
if len(created) == len(s):
ans.append(''.join(created))
return
for ch in remaining:
if (remaining[ch]<=0):
continue
remaining[ch] -=1
created.append(ch)
helper(created, remaining)
remaining[ch] +=1
created.pop()
counts = {}
for i in range(len(s)):
if s[i] not in counts:
counts[s[i]] = 1
else:
counts[s[i]]+= 1
helper([], counts)
print(len(set(ans)))
return ans
【问题讨论】:
-
是的,不要那样做。
-
我应该避免在迭代期间更改列表/集吗?正如您在上面的示例中看到的,我将不得不创建副本以避免空间复杂度上升。
-
您是因为对实现细节感到好奇而询问,还是有实际使用它的意图?对于列表,我偶尔会在迭代时修改,因为它相当可预测且方便,但我认为即使是我也不敢在迭代时修改 set。或者也许我只是还没有一个用例......
-
在您的
permutations/helper中,空间复杂度非常小。您正在处理排列,无论如何数据都会很小,否则您的结果会爆炸。但是如果你确实想在那里节省时间和空间,我建议只给helper一个 list 和一个 index,这意味着助手仍将置换该索引处的所有内容之后。或类似的东西。 -
顺便说一句,刚刚看到你的
set([str[i] for i in range(len(str))])。这与set(str)相同。并且最好不要调用变量str(遮蔽了您无法再访问的内置变量,而且它令人困惑,因为人们希望它是内置变量)。
标签: python set iteration python-internals