在列表中查找重复项并仅在其中一个上运行

时间:2017-12-15 09:50:03

标签: python python-3.x list

我扩展并添加了一个新问题。

我有一个清单:

li = [2, 3, 1, 4, 2, 2, 2, 3, 1, 3, 2] 

然后我会识别哪个值最常出现,我在变量i2中保留哪个值:

f = {}
for item in li:
    f[item] = f.get(item, 0) + 1   

for i in f:
    if f[i]==int(max(f.values())):
       i2 = i

稍后重复的所有值都会增加10,但除了最大值之外。这是我使用的代码:

for i in range(len(li)):
    for x in range(i + 1, len(li)):
        if li[i] == li[x] and li[i] != i2:
           li[x] = li[x] + 10

在此操作之后,我得到:

li = [2, 3, 1, 4, 2, 2, 2, 13, 11, 23, 2]

如您所见,最常见的值是2,因此它保持不变。例如,3发生三次,并且从所有三个新值创建3,3 + 10,3 + 20.并且与值的其余部分相同(除了2)。 但是如果两个最大值彼此相邻(或者在更长的序列中),我想逐个增加这个序列中的每个后续值,并得到:

li = [2, 3, 1, 4, 2, 12, 22, 13, 11, 23, 2] 

怎么做? 我现在可以在新循环上执行相同的操作,但已经在更改的列表上并应用条件li[i] == li[i+1],但也许可以在当前循环中完成?

4 个答案:

答案 0 :(得分:5)

首先,您应该使用collections.Counter来获取列表中元素的计数并找到most_common元素。

li = [2, 3, 1, 4, 2, 2, 2, 3, 1, 3, 2] 
l2 = collections.Counter(li).most_common(1)[0][0]

然后,如果当前元素是最常见元素的第一个匹配项,则可以使用第二个Counter作为运行计数,并将其重置为0。然后使用该计数器将10的倍数加到数字上,然后递增它。

running = collections.Counter()
last = None
for i, e in enumerate(li):
    if e == l2 and e != last:
        running[e] = 0
    li[i] = e + 10 * running[e]
    running[e] += 1
    last = e

之后,li[2, 3, 1, 4, 2, 12, 22, 13, 11, 23, 2]

答案 1 :(得分:2)

以下是嵌套循环的一个块中的解决方案:

import numpy as np
from collections import Counter

li = [2, 3, 1, 4, 2, 2, 2, 3, 1, 3, 2]
#Get most common
i2=Counter(li).most_common()[0][0]

for val in set(li): #loop over all unique values in li
    inds=np.where([i==val for i in li])[0] #get array of indices where li==val
    #special case for i2:
    if val==i2:
        c=1
        for ind in range(1,len(inds)):
            if inds[ind]==inds[ind-1]+1:
                li[inds[ind]]=li[inds[ind]]+10*c
                c+=1
            else:
                c=1
    #not i2:
    else:
        c=1
        for ind in range(1,len(inds)):
            li[inds[ind]]=li[inds[ind]]+10*c
            c+=1

它返回:

print(li)
[2, 3, 1, 4, 2, 12, 22, 13, 11, 23, 2]

一步一步演练:

计数器是获取i2的一种快捷方式,我们想要零元素,它是列表中最常见元素的值(不是计数)。

然后循环遍历列表中的所有唯一值,首先获取列表中的li与值相等的索引。

然后如果val==i2它将乘数c初始化为1并且循环检查连续索引(NB。此循环从1开始,所以任何val的第一次出现从未触及),如果发现它增加乘数和li中的值,如果不是连续索引,则将乘数重置为1。

对于所有其他值,它只是循环索引(再次从第二个)增加值和乘数

答案 2 :(得分:1)

我希望我的问题是正确的。这是:

from collections import Counter


def fix_pivot(my_list, max_el):
    new_list = []
    inc = 0
    for item in my_list:
        if item == max_el:
            new_list.append(item + inc)
            inc += 10
        else:
            new_list.append(item)
            inc = 0
    return new_list

li = [2, 3, 1, 4, 2, 2, 3, 1, 3, 2]

counted_li = Counter(li)
pivot = counted_li.most_common(1)[0][0]

# operating on all elements except for the most frequent, see note 1
temp = {k:[k + 10*(v-i-1) for i in range(v)] for k, v in counted_li.items()}
new = [temp[k].pop() if k != pivot else k for k in li]

# operating on the most frequent element, see note 2
res = fix_pivot(new, pivot)
print(res)  # -> [2, 3, 1, 4, 2, 12, 13, 11, 23, 2] 

注意:

  1. 根据原始列表li中元素的频率,创建一个如下所示的字典(temp):

    {2: [32, 22, 12, 2], 3: [23, 13, 3], 1: [11, 1], 4: [4]}
    

    结合[temp[k].pop() if k != pivot else k for k in li]列表理解,它会产生一个非常(至少爱,pop动作)优雅的方式来获得要求的第一部分;递增所有不是最常见的元素。

  2. 对于第二个,奇怪的要求,最简洁的方法是使用一个函数(再次imo)。每次函数遇到最常见的元素时,它会递增增量(0 - > 10 - > 20),每次找到不同的元素时,它会将其重置为0.

答案 3 :(得分:1)

这是我的答案,但我认为tobias_k的答案是最优雅的。

from collections import Counter

li = [2, 3, 1, 4, 2, 2, 3, 1, 3, 2]
c = Counter(li)
mc = max(c, key=c.get)

mapper = {k: 0 for k in li}
out = []
for i, v in enumerate(li):
    if v == mc:
        if i > 0 and li[i - 1] == mc:
            mapper[v] += 10
            out.append(v + mapper[v])
        else:
            mapper[v] = 0
            out.append(v)
    else:
        out.append(v + mapper[v])
        mapper[v] += 10

print(out)
>>> [2, 3, 1, 4, 2, 12, 13, 11, 23, 2]