我一直在尝试在int类型的List中查找(并替换)相邻的相似(相等值)元素。
在实施该程序时,我只记住一个约束条件:-也就是说,查找/替换彼此相邻的长度=(或>)3的元素。
以下是我所做的:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new[] {2, 2, 2, 3, 3, 4, 4, 4, 4};
for (var i = 2; i < list.Length; i++)
{
if (list[i] == list[i - 1] && list[i] == list[i - 2])
{
list[i] = 0;
list[i - 1] = 0;
list[i - 2] = 0;
}
}
foreach(int item in list)
{
Console.Write(item);
}
Console.ReadKey();
}
}
我将用0替换所有相邻的相似/相等值。但有一个问题:如果重复值长度为3/6/9等,则代码运行良好;如果重复数字的长度不是3/6/9,则代码不会将数字值更改为0等
如果运行该程序,您将看到以下输出:000330004(因为有3个2,所以工作正常,但因为有4个4,所以它忽略了最后一个数字,没有将其转换为0)。
我需要什么:我了解正在发生的事情,以及为什么会发生。我就是不想让它发挥作用。如果有人能告诉我怎么做,我将不胜感激。谢谢
这应该适用于任意数量的整数:
namespace Test
{
using System;
using System.Collections.Generic;
class MainClass
{
public static void Main (string[] args)
{
List<int> data = new List<int> ();
data.AddRange (new int[] { 2, 2, 2, 3, 3, 4, 4, 4, 4 });
int instance_counter = 0;
int previous_end = 0;
for (int i = 0; i < data.Count - 1; i++) {
instance_counter++;
if (data [i] != data [i + 1]) {
if (instance_counter > 2) {
for (int j = previous_end; j < i + 1; j++) {
data [j] = 0;
}
previous_end = i + 1;
}
instance_counter = 0;
previous_end = i + 1;
}
}
if (instance_counter > 2) {
for (int j = previous_end; j < data.Count; j++) {
data [j] = 0;
}
}
foreach (int x in data) {
Console.WriteLine (x);
}
}
}
}
最后一个没有被转换,因为34的在它首先被转换为0之前。
第7次迭代:{00033**444**4}
第8次迭代:{00033**000**4}
第9次迭代:{000330004} //the 9th iteration loops over the 8th one.
你应该做的是找到任何重复数字的开始和结束,然后修改它们的值。您当前的方法将替换3个类似的值,每次替换3个。
当你找到3个重复的元素时,不要替换它们——计算它们。保留最后一个值和等于该值的元素数(在当前值之前)。当值更改为其他值时,如果计数的元素数为>=3
,则替换计数的元素。
int previous = list[0];
int count = 1;
int i;
for (i = 1; i < list.Length; i++)
{
if (list[i] == previous)
{
count++;
}
else
{
if (count >= 3)
{
for (int j = 1; j <= count; j++)
list[i-j] = 0;
}
count = 1;
previous = list[i];
}
}
// repeat the else logic from the loop above:
if (count >= 3)
{
for (int j = 1; j <= count; j++)
list[i-j] = 0;
}
从概念上讲,这与您接受作为问题答案的想法相同。在List<字符串>
还有一个使用LINQ的解决方案。
List<int> data = new List<int>();
data.AddRange(new int[] { 2, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5 });
var consecutiveIndexes = data.Select((value, index) => new { Index = index, Value = value })
.OrderBy(container => container.Index)
.GroupBy(container => container.Value, group => group.Index)
// Get consecutive indexes where count > 2 and elements are consecutive
.Where(group => group.Count() > 2 &&
//return next index if previous index is one less than the next index else -1
group.Aggregate((prevIndex, nextIndex) => prevIndex + 1 == nextIndex ? nextIndex : -1) > -1)
.SelectMany(index => index);
var filteredData = data.Select((x, i) => consecutiveIndexes.Contains(i) ? 0 : x);
我意识到你已经有了答案,但我睡不着,看到你的问题让我有了一些事情要做。我本来想使用Enumerable.Aggregate
,但无法用一种好的方式来做,但仍然想尝试用另一种方式来解决你的问题。
我用一些随机列表(包括一个空列表,当然还有你的列表)测试了它,它适用于我能想到的所有情况。
edit:我再次查看了您的代码,得出了一个简单但无聊的答案(只对您所做的内容进行了微小的修改),因此为了完整起见,我发布了(方法2)。
方法1:"有趣"的方式
using System;
using System.Collections.Generic;
using System.Linq;
public class Test
{
public static void Main()
{
var list = new[] {2, 2, 2, 3, 3, 4, 4, 4, 4};
// tuples is a list of Tuple<current value, number of repetitions of value>
var tuples = new List<Tuple<int, int>>();
var currentTuple = Tuple.Create(0, 0);
foreach ( var value in list )
{
bool newValue = value != currentTuple.Item1;
if ( newValue && currentTuple.Item2 != 0 )
tuples.Add(currentTuple);
currentTuple = Tuple.Create(
value,
newValue ? 1 : currentTuple.Item2 + 1);
}
tuples.Add(currentTuple);
var result = new List<int>();
foreach ( var tuple in tuples )
result.AddRange(Enumerable.Repeat(tuple.Item2 > 2 ? 0 : tuple.Item1, tuple.Item2));
foreach ( var item in result )
Console.WriteLine(item);
}
}
方法2:钻孔方式
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
var list = new[] {2, 2, 2, 3, 3, 4, 4, 4, 4};
var copy = list.ToArray();
for (var i = 2; i < list.Length; i++)
{
if (list[i] == list[i - 1] && list[i] == list[i - 2])
{
copy[i] = 0;
copy[i - 1] = 0;
copy[i - 2] = 0;
}
}
foreach ( int item in copy )
Console.Write(item);
}
}