如何以偶数频率顺序打印字典键

时间:2019-04-01 19:12:16

标签: python python-3.x

我想以偶数频率打印出字典键,值对

  

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

5 个答案:

答案 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个列表。其次,交织AB。我们需要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]