C# 为什么要列出<;T>;。删除范围(索引、计数)在索引之前更改值?
我正在实现一个经典的遗传算法。在交叉阶段,我发现了一些奇怪的行为C# 为什么要列出<;T>;。删除范围(索引、计数)在索引之前更改值?,c#,.net,list,ienumerable,genetic-algorithm,C#,.net,List,Ienumerable,Genetic Algorithm,我正在实现一个经典的遗传算法。在交叉阶段,我发现了一些奇怪的行为 private static void Crossover(ref List<CrossoverPair> pairs) { var random = new Random(); //TODO debug this foreach (var pair in pairs) { for (var i = 0; i < pair.First.Chromosomes.Cou
private static void Crossover(ref List<CrossoverPair> pairs)
{
var random = new Random();
//TODO debug this
foreach (var pair in pairs)
{
for (var i = 0; i < pair.First.Chromosomes.Count; i++)
{
var locus = random.Next(1, 12);
var crossoverLength = pair.First.Chromosomes[i].Genes.Count - locus;
var swapFirst = pair.First.Chromosomes[i].Genes.Skip(locus).Take(crossoverLength).ToList();
var swapSecond = pair.Second.Chromosomes[i].Genes.Skip(locus).Take(crossoverLength).ToList();
pair.First.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
pair.First.Chromosomes[i].Genes.AddRange(swapSecond);
pair.Second.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
pair.Second.Chromosomes[i].Genes.AddRange(swapFirst);
}
}
}
专用静态无效交叉(参考列表对)
{
var random=新的random();
//要调试这个吗
foreach(成对变量对)
{
for(var i=0;i
每个染色体包含12个基因。它从一个随机定义的位点开始交换同源部分。例如,如果我们有locus=8
和crossoverLength=4
,我们首先使用removange
从基因[8]
到基因[11]
,然后使用AddRange
从另一个染色体添加基因
有时会发生一些奇怪的事情:当我们使用RemoveRange
时,基因[7]
(在本例中)将其值从0更改为1或从1更改为0。它不是每次迭代都会发生,有时一切都很好。我注意到,对于locus=7..11
,这种情况更为常见
它不会对算法造成太大的伤害(只是更多的突变:D)。但有人知道为什么它会颠倒价值观吗
更新:
非常感谢BJ Myers给出的无可争议的答案。
其他人,谁将阅读这篇文章后,可能会感兴趣,为什么会发生。解释得很好。
RemoveRange
没有更改指定索引之前的值。这似乎是因为您的索引被关闭了1
请看这一行:
pair.First.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
如果我们假设(如您的示例所示)locus=8
,因此crossoverLength=4
,那么所需的行为将是通过[11]
删除索引为[8]
的元素。但是,由于您已经从轨迹中减去了一个
,因此将7
作为第一个参数传递给RemoveRange
,从而通过[10]
删除元素[7]
对于调用RemoveRange
,正确的代码不应包含-1
偏移量:
pair.First.Chromosomes[i].Genes.RemoveRange(locus, crossoverLength);
您认为元素
[7]
改变的行为实际上是元素[7]
通过[10]
被移除的结果,而元素先前位于[11]
的位置向下移动到[7]
。如果您的“基因”始终是二进制的,则值有50/50的可能性会因RemoveRange
调用而“更改”。RemoveRange
不会更改指定索引之前的值。这似乎是因为您的索引被关闭了1
请看这一行:
pair.First.Chromosomes[i].Genes.RemoveRange(locus - 1, crossoverLength);
如果我们假设(如您的示例所示)locus=8
,因此crossoverLength=4
,那么所需的行为将是通过[11]
删除索引为[8]
的元素。但是,由于您已经从轨迹中减去了一个
,因此将7
作为第一个参数传递给RemoveRange
,从而通过[10]
删除元素[7]
对于调用RemoveRange
,正确的代码不应包含-1
偏移量:
pair.First.Chromosomes[i].Genes.RemoveRange(locus, crossoverLength);
您认为元素[7]
改变的行为实际上是元素[7]
通过[10]
被移除的结果,而元素先前位于[11]
的位置向下移动到[7]
。如果您的“基因”始终是二进制的,那么值有50/50的可能性会因RemoveRange
调用而“改变”