在列表中查找重复的数字并使其唯一

时间:2017-05-25 18:54:05

标签: python

我试图实现遗传算法,并且需要这个用于我的交叉功能。我需要弄清楚的是以下内容。 如果我有列表

[0, 1, 6, 7, 5, 4, 3, 2, 1]

它有重复的元素。我想最终得到列表

[0, 8, 6, 7, 5, 4, 3, 2, 1]

我最终得到这个列表的原因是我从左到右看每个元素。我在索引1处看到了#1;' 1'它也存在于列表中。因此我将其更改为不在列表中的元素。列表中的最小元素是0,最大元素是len(list)-1。

在这种情况下,列表的顺序很重要。因此,我不认为将其转换为一组是合适的。我不想失去元素的顺序。我只是在改变列表中重复的元素。

另一个例子是

[0, 1, 2, 7, 3, 4, 3, 2, 1]

会变成

[0, 5, 6, 7, 8, 4, 3, 2, 1]

所以这里发生的事情是我在索引1处看到了数字1,并且意识到从0到8的范围,我错过了数字5.所以1被替换为5.类似地,我为索引2做了,我用6代替了。最后我为索引4做了这个,最初是3,但是被8替换,因为它是重复的。

我在想的是递增重复的数字,然后检查它是否重复,并重复直到列表中的每个元素都是唯一的。但是,我无法想办法做到这一点。

5 个答案:

答案 0 :(得分:2)

因此,除非我弄错了,否则您选择更换的号码背后没有真正的方法,只是您认为缺少的号码。如果是这种情况,则会产生所需的结果。

l = [0, 1, 2, 7, 3, 4, 3, 2, 1]
missing = [n for n in range(len(l)) if n not in set(l)]

for num in l:
    if l.count(num) > 1:
        ix = l.index(num)
        try:
            l[ix] = missing.pop(0)
        except IndexError:
            break

print l
>>[0, 5, 6, 7, 8, 4, 3, 2, 1]

答案 1 :(得分:0)

更新:这可以通过more_itertools.locate来实现,它会找到给定条件的索引。

import itertools as it
import collections as ct

from more_itertools import locate 


def replace_repeated(lst):
    """Return a list of unique values with a range ~ list size."""

    def excluded_indices():
        """Yield indices of all but the index of the last repeated element."""
        for i, n in repeated.items():
            yield from it.islice(locate(lst, pred=lambda x: x == i), 0, n-1)

    repeated = {k:v for k, v in ct.Counter(lst).items() if v > 1}
    missing = (i for i, _ in enumerate(lst) if i not in set(lst))
    for i in excluded_indices():
        lst[i] = next(missing)
    return lst

步骤

  1. 查找k中所有重复元素的值(v)和频率(lst)。
  2. 查找与lst的大小成比例的所有缺失数字。
  3. 查找excluded_indices - repeated元素的索引(每个repeated值的最终出现除外)。
  4. 对于每个排除的索引,使用下一个lst号码覆盖missing中的元素。
  5. 测试

    import nose.tools as nt
    
    def test_repeated(f):
        """Verify repeated terms are replaced with values."""
        nt.eq_(f([0, 1, 6, 7, 5, 4, 3, 2, 1]),              # given
                 [0, 8, 6, 7, 5, 4, 3, 2, 1])
        nt.eq_(f([0, 1, 2, 7, 3, 4, 3, 2, 1]),              # given
                 [0, 5, 6, 7, 8, 4, 3, 2, 1])
        nt.eq_(f([0, 1, 6, 7, 1, 4, 1, 2, 1]),              # multiples (not only duplicates)
                 [0, 3, 6, 7, 5, 4, 8, 2, 1])
        nt.eq_(f([0, 1, 6, 2, 5, 3, 3, 2, 1]),              # multiples of any element
                 [0, 4, 6, 7, 5, 8, 3, 2, 1])
    
    test_repeated(f=replace_repeated)
    

    可选,这里是locate的代码,如果需要,可以直接实现并避免pip安装:

    def locate(iterable, pred=bool):
        return it.compress(it.count(), map(pred, iterable))
    

答案 2 :(得分:0)

您需要分两个阶段执行此操作(或者让其他事情分两个阶段为您完成) - 首先找到缺少的值,然后通过列表替换缺少值的重复项。类似的东西:

def normalize_list(data):
    # data = list(data)  # uncomment if you don't want to modify the source list
    # use xrange() instead of range() on Python 2.x
    missing_keys = [i for i in range(len(data)-1, -1, -1) if i not in set(data)]
    for index, value in enumerate(data):
        try:
            if data.index(value, index+1):
                data[index] = missing_keys.pop()
        except ValueError:
            pass
    return data

print(normalize_list([0, 1, 6, 7, 5, 4, 3, 2, 1]))
# prints: [0, 8, 6, 7, 5, 4, 3, 2, 1]
print(normalize_list([0, 1, 2, 7, 3, 4, 3, 2, 1]))
# prints: [0, 5, 6, 7, 8, 4, 3, 2, 1]

这应该适用于任何大小的列表。

<强>更新

考虑到list.index()的缓慢,这里没有它的版本 - 它看起来反直觉(再多一个循环),但它快了近4倍(并且列表越长,相对于第一个例子的速度越快,内存使用量就越多:

def normalize_list(data):
    # data = list(data)  # uncomment if you don't want to modify the source list
    key_lookup = dict.fromkeys(data, -1)
    # use xrange() instead of range() on Python 2.x
    missing_keys = [i for i in range(len(data)-1, -1, -1) if i not in key_lookup]
    for i in data:
        key_lookup[i] += 1
    for index, value in enumerate(data):
        try:
            if key_lookup[value]:
                data[index] = missing_keys.pop()
                key_lookup[value] -= 1
        except ValueError:
            pass
    return data

答案 3 :(得分:0)

这是另一种方法:

  1. 计算存储列表中每个唯一值的最后一个索引的字典。
  2. 创建缺失值的生成器。
  3. 使用列表推导替换列表中每个唯一元素的最后一个值。
  4. e.g。

    xs = [0, 1, 6, 7, 5, 4, 3, 2, 1]
    fixed  = {x: i for i, x in enumerate(xs)}
    spares = iter(x for x in range(len(xs)) if x not in fixed)
    res    = [x if i == fixed[x] else next(spares)
                for i, x in enumerate(xs)]
    

答案 4 :(得分:0)

def returnModifiedList(x):

 #find indices where there is a repeat
 storage=[]; indices = []
 for i in range(len(x)-1,-1,-1):
     if x[i] in storage:
         indices.append(i)
     else:
         storage.append(x[i])

 #find values that are missing
 s = sorted(list(set(x)))
 missing = list(reversed([i for i in range(len(x)) if (i not in s)]))

 #fill in repeats with missing values
 for i in range(len(indices)):
     x[indices[i]] = missing[i]

 return x



x = [0, 1, 2, 7, 3, 4, 3, 2, 1]
results = returnModifiedList(x)
print results