在List <int> </int>中查找(并替换)相邻的相等/相似元素

时间:2015-02-22 02:11:41

标签: c# algorithm list foreach

我一直在尝试在类型为int的List中找到(并替换)相邻的相似(等值)元素。

在实施程序时,我只记得一个约束: - 也就是说,查找/替换彼此相邻的元素的长度为=(或&gt;)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)。

我需要什么:我理解发生了什么,以及为什么会发生这种情况。我似乎无法拥有它,因为我希望它能够工作。如果有人能告诉我怎么做,我会很感激。感谢。

5 个答案:

答案 0 :(得分:1)

最后一个没有被转换,因为3 4的在它首先被转换为0之前。

第7次迭代:
{00033**444**4}
第8次迭代:
{00033**000**4}
第9次迭代:
{000330004} //the 9th iteration loops over the 8th one.

您应该做的是找到任何重复数字的开头和结尾,然后修改它们的值。您当前的方法替换了3个类似的值,一次3个。

答案 1 :(得分:1)

当你找到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;
} 

从概念上讲,您接受的问题是Count similar adjacent items in List<string>

的答案

答案 2 :(得分:1)

这适用于任意数量的整数:

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);
            }
        }
    }
}

答案 3 :(得分:1)

使用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);

答案 4 :(得分:0)

我意识到你已经有了答案,但我无法入睡,看到你的问题让我有意思去做。我原本想使用Enumerable.Aggregate,但无法以漂亮的方式进行,但仍想尝试以不同的方式解决问题。

我已经使用一些随机列表(包括空列表,当然还有您的列表)测试了它,它适用于我能想到的所有情况。

编辑:我再次看了你的代码并提出了一个更简单但更无聊的答案(只对你所做的做了很小的改动)所以发布了(方法2)完整性。


方法1:&#39; fun&#39;方式

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);
    }
}