【问题标题】:Finding duplicates in list and operating only on one of them在列表中查找重复项并仅对其中一个进行操作
【发布时间】:2017-12-15 09:50:02
【问题描述】:

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

我有一个清单:

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、3 + 10、3 + 20。其余的值相同(2 除外)。 但是,如果两个最大值彼此相邻(或以更长的序列),我想在这样的序列中将每个后续增加 10,并得到:

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

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

【问题讨论】:

  • 和以前一样的问题?
  • 是的,因为我添加了更多解释以使其更易于理解。
  • "但是如果两个最大值彼此相邻,我只想将第二个增加 10" 这是让这令人头疼的部分。我有一个不尊重这条规则的非常优雅的解决方案。您还必须更精确。如果三个或更多最常见的值依次出现怎么办?如果两个或多个最常见的值按顺序出现,但这些值不同,因为在原始列表中出现最多次数的值不止一个,该怎么办?
  • 也许从更一般的角度思考或跳出框框思考可能会有所帮助。为了帮助我们更好地理解规则,您能否描述(在更高的层次上)您正在寻求解决的问题?
  • @timgeb 哦,请不要... xD 为什么不[1,1,0,1,1,1] => [1, 11, 0, 1, 11, 21]

标签: python python-3.x list


【解决方案1】:

首先,您应该使用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]

【讨论】:

  • 这是一个绝妙的解决方案。
【解决方案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]

逐步演练:

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

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

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

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

【讨论】:

    【解决方案3】:

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

    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] 列表理解,它产生了一种非常优雅的方式来获取第一部分的需求;递增所有不是最常见的元素。

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

    【讨论】:

    • 工作优雅! :) 没想到会是这么复杂的问题:谢谢!
    【解决方案4】:

    这是我的答案,但我认为 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]
    

    【讨论】:

    • 我也这么认为,但感谢您的努力和解决方案:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-07-10
    • 2020-06-10
    • 2018-11-14
    • 1970-01-01
    • 1970-01-01
    • 2017-09-02
    • 1970-01-01
    相关资源
    最近更新 更多