在列表中<int>查找(和替换)相邻的相等/相似元素



我一直在尝试在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);
    }
}

最新更新