我想以偶数频率打印出字典键,值对
a = dict('A':3,'B':5} => ['A','B','A','B','A','B','B','B']
a = dict('A':4,'B':1} => ['A','B','A','A','A']
我知道我可以使用while循环来打印每个键并每次都删除计数,直到所有键的所有值都为0,但是否有更好的方法呢?
def func(d: dict):
res = []
while any(i > 0 for i in d.values()):
for k, c in d.items():
if c > 0:
res.append(k)
d[k] -= 1
return res
答案 0 :(得分:4)
(我假设您使用的Python版本可以保证字典的迭代顺序)
这是一个itertools-y方法。它会为每个字母创建一个生成器,该生成器会按给定的次数生成字母,并将所有这些字母与zip_longest
结合在一起,从而使它们平均生成。
from itertools import repeat, zip_longest
def iterate_evenly(d):
generators = [repeat(k, v) for k,v in d.items()]
exhausted = object()
for round in zip_longest(*generators, fillvalue=exhausted):
for x in round:
if x is not exhausted:
yield x
print(list(iterate_evenly({"A": 3, "B": 5})))
print(list(iterate_evenly({"A": 4, "B": 1})))
结果:
['A', 'B', 'A', 'B', 'A', 'B', 'B', 'B']
['A', 'B', 'A', 'A', 'A']
尽管很难阅读,但您可以用更少的行来做相同的事情。
from itertools import repeat, zip_longest
def iterate_evenly(d):
exhausted = object()
return [x for round in zip_longest(*(repeat(k, v) for k,v in d.items()), fillvalue=exhausted) for x in round if x is not exhausted]
print(iterate_evenly({"A": 3, "B": 5}))
print(iterate_evenly({"A": 4, "B": 1}))
答案 1 :(得分:2)
单线。
首先,创建一个包含两个元素的列表:A
s列表和B
s列表:
>>> d = {'A': 3, 'B': 5}
>>> [[k]*v for k, v in d.items()]
[['A', 'A', 'A'], ['B', 'B', 'B', 'B', 'B']]
[k]*v
的意思是:具有v
k
s个列表。其次,交织A
和B
。我们需要zip_longest
,因为zip
将在第一个列表结束后停止:
>>> import itertools
>>> list(itertools.zip_longest(*[[k]*v for k, v in d.items()]))
[('A', 'B'), ('A', 'B'), ('A', 'B'), (None, 'B'), (None, 'B')]
现在,只需将列表弄平并删除None
值:
>>> [v for vs in itertools.zip_longest(*[[k]*v for k, v in d.items()]) for v in vs if v is not None]
['A', 'B', 'A', 'B', 'A', 'B', 'B', 'B']
其他示例:
>>> d = {'A': 4, 'B': 1}
>>> [v for vs in itertools.zip_longest(*[[k]*v for k, v in d.items()]) for v in vs if v is not None]
['A', 'B', 'A', 'A', 'A']
答案 2 :(得分:0)
您可以将sum
与生成器理解一起使用:
res = sum(([key]*value for key, value in d.items()), [])
这利用了一个事实,即sum
除了序列乘法(+
)之外,还可以“添加”任何可以使用"A"*4 == "AAAA"
运算符的东西,例如列表。
如果您希望订单随机化,请使用random
模块:
from random import shuffle
shuffle(res)
如Thierry Lathuille所述,如果您想按原始顺序循环显示值,则可以使用一些itertools魔术:
from itertools import chain, zip_longest
res = [*filter(
bool, # drop Nones
chain(*zip_longest(
*([key]*val for key, val in d.items()))
)
)]
答案 3 :(得分:0)
作为复制和zip_longest
方法的替代方法,让我们尝试简化OP的原始代码:
def function(dictionary):
result = []
while dictionary:
result.extend(dictionary)
dictionary = {k: v - 1 for k, v in dictionary.items() if v > 1}
return result
print(function({'A': 3, 'B': 5}))
print(function({'A': 4, 'B': 1}))
输出
% python3 test.py
['A', 'B', 'A', 'B', 'A', 'B', 'B', 'B']
['A', 'B', 'A', 'A', 'A']
%
尽管看起来可能不是这样,但是与OP的原始代码不同,它对字典参数没有破坏作用。
答案 4 :(得分:0)
也可以使用通过扩展每个字典条目而形成的(位置,字符)元组来完成此操作:
a = {'A': 3, 'B': 5}
result = [c for _,c in sorted( (p,c) for c,n in a.items() for p,c in enumerate(c*n))]
print(result) # ['A', 'B', 'A', 'B', 'A', 'B', 'B', 'B']
如果字典的顺序可用,则可以放弃排序并使用它:
result = [c for i in range(max(a.values())) for c,n in a.items() if i<n]