我正在尝试根据字符串中存在的1来将某些数字的二进制字符串分组在一起。
这不起作用:
s = "0 1 3 7 8 9 11 15"
numbers = map(int, s.split())
binaries = [bin(x)[2:].rjust(4, '0') for x in numbers]
one_groups = dict.fromkeys(range(5), [])
for x in binaries:
one_groups[x.count('1')] += [x]
预期字典one_groups
必须为
{0: ['0000'],
1: ['0001', '1000'],
2: ['0011', '1001'],
3: ['0111', '1011'],
4: ['1111']}
但是我知道
{0: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
1: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
2: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
3: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111'],
4: ['0000', '0001', '0011', '0111', '1000', '1001', '1011', '1111']}
到目前为止,唯一起作用的是如果我使用one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
而不是one_groups[x.count('1')] += [x]
但是为什么会这样呢?如果我没记错的话,dict[key]
是否不应该返回该字典的值,类似于dict.get(key)
的工作方式?我已经看到了该线程Why dict.get(key) instead of dict[key]?,但是对于这种特殊情况,它没有回答我的问题,因为我确定该程序并不是要获取KeyError
我也尝试过one_groups[x.count('1')].append(x)
,但这也不起作用。
问题是可变性:
one_groups = dict.fromkeys(range(5), [])
-这会将与值相同的数组传递给所有键。因此,如果更改一个值,则全部更改。
基本上与说相同:
tmp = []
one_groups = dict.fromkeys(range(5), tmp)
del tmp
如果要使用新列表,则需要循环执行-显式for
循环或dict理解:
one_groups = {key: [] for key in range(5)}
此事物将为每个键“执行” []
(等于list()
),从而使值具有不同的列表。
get
为什么起作用?因为您显式获取了当前列表,但是+
创建了新的结果列表。 one_groups[x.count('1')] = one_groups.get(x.count('1')) + [x]
或one_groups[x.count('1')] = one_groups[x.count('1')] + [x]
都没关系-重要的是+
。
[我知道每个人都说a+=b
只是a=a+b
,但是优化的实现可能有所不同-在列表的情况下,+=
只是.append
,因为我们知道我们希望将结果保存在当前变量中,因此创建新列表将浪费内存。
问题在使用one_groups = dict.fromkeys(range(5), [])
您可以改用它:one_groups = {i:[] for i in range(5)}
这是dict的fromkeys
方法的帮助。
关于内置功能fromkeys的帮助:
buildins.type实例的fromkeys(iterable,value = None,/)方法使用可迭代键并将值设置为value创建一个新字典
这表示fromkeys会接受一个值,即使它是可调用的,它也会先对其求值,然后将该值分配给所有dict键。
列表在Python中是可变的,因此它将分配相同的空列表引用,并且一项更改将影响所有列表。
改为使用defaultdict:
>>> from collections import defaultdict
>>> one_groups = defaultdict(list)
>>> for x in binaries:
one_groups[x.count('1')] += [x]
>>> one_groups = dict(one_groups) # to stop default dict behavior
这将接受对不存在的键的分配,并且值将默认为空列表(在这种情况下)。