优化计数列表中元素之间的变化

时间:2018-07-08 21:57:32

标签: python list for-loop list-comprehension

我有一些工作代码来跟踪列表元素之间的“变化”-使得任何两个不相同的连续元素构成一个变化。此处的代码很容易理解。

testlist = ['red','red','blue','red','red','black','yellow','black','yellow','blue']

第一个redred不会触发任何更改,但是下一个redblue则会触发更改。 我也想对每种颜色进行汇总。

# Set Tally counters to 0 and a unique key
red = 0
blue = 0
black = 0
yellow = 0
key = 40006

for i in range(len(testlist)-1):
    if (testlist[i] == (testlist[i+1])):
        print("No Change")
    else:
        print("Change to: " + str(testlist[i+1]))
        if testlist[i+1] == 'red':
            red = red + 1
        elif testlist[i+1] == 'blue':
            blue = blue + 1
        elif testlist[i+1] == 'black':
            black = black + 1
        elif testlist[i+1] == 'yellow':
            yellow = yellow + 1
dictfordf = {'key':key, 'red':red,'blue':blue,'black':black,'yellow':yellow}

这有效并正确输出{'black': 2, 'blue': 2, 'key': 40006, 'red': 1, 'yellow': 2}

当唯一元素的数量增加(此示例中只有4种唯一颜色)到10时,if/elif变得非常冗长。

我的两个问题是:

  • 是否有更简洁的方法来实现这一目标?
  • 是否有更快的方法来执行此任务?

3 个答案:

答案 0 :(得分:4)

首先,由于您的目标是构建一个dict,所以只需动态构建该dict,而不是构建一堆单独的变量,然后将其放在dict的最后即可。

您也可以使用Counter而不是普通字典,这样就不必担心检查颜色是否已经存在。

我们正在使用它,不需要在已经是字符串的东西上调用str,并且到处都有很多不必要的括号。

所以:

from collections import Counter
dictfordf = Counter()
dictfordf['key'] = 40006
for i in range(len(testlist)-1):
    if testlist[i] == testlist[i+1]:
        print("No Change")
    else:
        print("Change to: " + testlist[i+1])
        dictfordf[testlist[i+1]] += 1

存储'key'的值确实不算是一个小事,所以您可能要考虑使用defaultdict或{{1 }}来代替普通字典。但我认为这还不错。

当然,如果setdefault可能是'key'中的元素之一,那么这将使密钥递增。但是,如果可能的话,尚不清楚在这种情况下应该发生什么 ,因此也不清楚您要如何解决它。


同时,您可以通过迭代相邻对来使事情变得简洁。请参阅itertools文档中的testlist食谱。但是,当然,这会将pairwise的定义添加到您的代码中(或者您可以从pairwisemore-itertools之类的第三方库中导入它。)

所以:

toolz

您可以使用from collections import Counter from itertools import tee def pairwise(iterable): "s -> (s0,s1), (s1,s2), (s2, s3), ..." a, b = tee(iterable) next(b, None) return zip(a, b) dictfordf = Counter() dictfordf['key'] = 40006 for prev, current in pairwise(testlist): if prev == current: print("No Change") else: print("Change to: " + current) dictfordf[current] += 1 groupby中的unique_justseen配方进一步抽象事物。我认为这会掩盖而不是澄清您在itertools的输出位置,但是,假设您了解print的版本,则有必要对它们进行阅读,并尝试编写两种选择,至少锻炼。

答案 1 :(得分:1)

我对这个问题的看法:

from collections import Counter

testlist = ['red','red','blue','red','red','black','yellow','black','yellow','blue']

def changes(data):
    last = data[0]
    for i in data:
        if last != i:
            yield i
        last = i

c = Counter(changes(testlist))
c['key'] = 40006
print(dict(c))

输出:

{'yellow': 2, 'red': 1, 'key': 40006, 'blue': 2, 'black': 2}

答案 2 :(得分:0)

我的拍摄使用zip成对浏览列表,非常简洁。像其他人一样,它使用Counter,我同意这是工作的正确工具。

from collections import Counter

testlist = ['red','red','blue','red','red','black','yellow','black','yellow','blue']

def count_changes(data):
    c = Counter()
    c['key'] = 40006
    for item1, item2 in zip(data, data[1:]):
        if item1 != item2:
            c[item2] += 1
    return c

print(count_changes(testlist))

输出:

Counter({'key': 40006, 'blue': 2, 'black': 2, 'yellow': 2, 'red': 1})

尚不清楚如果"key"出现在测试列表中应该是什么正确的行为,但是直接修改此代码来处理它应该很简单。