我试图实现遗传算法,并且需要这个用于我的交叉功能。我需要弄清楚的是以下内容。 如果我有列表
[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替换,因为它是重复的。
我在想的是递增重复的数字,然后检查它是否重复,并重复直到列表中的每个元素都是唯一的。但是,我无法想办法做到这一点。
答案 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
步骤
k
中所有重复元素的值(v
)和频率(lst
)。lst
的大小成比例的所有缺失数字。excluded_indices
- repeated
元素的索引(每个repeated
值的最终出现除外)。lst
号码覆盖missing
中的元素。测试
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)
这是另一种方法:
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