消除列表元素的连续重复

时间:2011-04-20 11:37:52

标签: c# list

是否有一种“好的”方法可以消除列表元素的 连续重复

示例:

["red"; "red"; "blue"; "green"; "green"; "red"; "red"; "yellow"; "white"; "white"; "red"; "white"; "white"] 

应该成为

["red"; "blue"; "green"; "red"; "yellow"; "white"; "red"; "white"]

- “好”我的意思是对新用户和快速执行最具可读性和可理解性:)

11 个答案:

答案 0 :(得分:60)

一个简单且易读的解决方案:

List<string> results = new List<string>();
foreach (var element in array)
{
    if(results.Count == 0 || results.Last() != element)
        results.Add(element);
}

答案 1 :(得分:19)

你可以推出自己的linq风格。

// For completeness, this is two methods to ensure that the null check 
// is done eagerly while the loop is done lazily. If that's not an issue, 
// you can forego the check and just use the main function.

public static IEnumerable<T> NonConsecutive<T>(this IEnumerable<T> input)
{
  if (input == null) throw new ArgumentNullException("input");
  return NonConsecutiveImpl(input);
}

static IEnumerable<T> NonConsecutiveImpl<T>(this IEnumerable<T> input)
{
   bool isFirst = true;
   T last = default(T);
   foreach (var item in input) {
      if (isFirst || !object.Equals(item, last)) {
          yield return item;
          last = item;
          isFirst = false;
      }
   }
}

并用作

array.NonConsecutive().ToArray()

优点是它被懒惰地评估,因此您可以在任何枚举上使用它而不必完全使用它,并将其与其他linq方法(例如:array.Where(i => i != "red").NonConsecutive().Skip(1).ToArray())链接。如果你没有这个要求,而你只想使用数组,那么Simon Bartlett的解决方案可能会稍微提高一些性能。

有关为何必须采用两种方法的详细信息,请参阅here

答案 2 :(得分:8)

您可以为此创建简单的通用方法,如下所示:

[编辑2] (非常感谢Eric Lippert)

    public static List<T> ExcludeConsecutiveDuplicates<T>(List<T> InputList)
    {
        object lastItem = null;
        List<T> result = new List<T>();

        for (int i = 0; i < InputList.Count; i++)
        {
            if (i==0 || Object.Equals(InputList[i],lastItem) != true)
            {
                lastItem = InputList[i];
                result.Add((T)lastItem);
            }
        }

        return result;
    }

答案 3 :(得分:5)

您可以在LINQ中执行此操作:

list.Aggregate(new List<string>(), 
   (current, next) => {
      if (current.Length <= 0 || current[current.Length-1] != next) current.Add(next);
      return current;
   });

基本上,这会创建一个初始为空的列表,在整个源列表中运行,并且只有在与目标列表的最后一项不同时才将项添加到目标列表。

如果没有LINQ,你可以轻松(可能更容易)做到这一点:

var target = new List<string>();
foreach (var item in list) {
   if (target.Length <= 0 || target[target.Length-1] != item) target.Add(item);
}

答案 4 :(得分:1)

解决:

IList<string> stringList = new List<string>() { "red", "red", 
                                                "blue", "green", 
                                                "green", "red", 
                                                "red", "yellow", 
                                                "white", "white", 
                                                "red", "white", "white" };      
  for (int i = 0; i < stringList.Count; i++)
  {
    // select the first element
    string first = stringList[i];

    // select the next element if it exists
    if ((i + 1) == stringList.Count) break;
    string second = stringList[(i + 1)];

    // remove the second one if they're equal
    if (first.Equals(second))
    {
      stringList.RemoveAt((i + 1));
      i--;
    }
  }
如果出现问题,请在评论中纠正我!

/ e:已编辑的代码,因此适用于“白色”,“白色”,“白色”,“白色”

答案 5 :(得分:1)

试试这个:

using System;    
using System.Linq;    
using System.Collections.Generic;

namespace RemoveDuplicates
{
    class MainClass
    {
        public static void Main (string[] args)
        {

            string[] a = new string[] 
            { "red", "red", "red", "blue", 
                      "green", "green", "red", "red", 
                      "yellow", "white", "white", "red", "white", "white" };

            for(int i = 0; i < a.Length; ++i)
                if (i == a.Length-1 || a[i] != a[i+1])
                    Console.WriteLine(a[i]);

        }
    }
}

输出:

red
blue
green
red
yellow
white
red
white

答案 6 :(得分:0)

功能方法:

var input = new[] {"red", "red", "blue", 
                   "green", "green", "red", "red", "yellow",
                   "white", "white", "red", "white", "white"};

var output = input.Aggregate(new List<string>(),
                             (runningOutput, value) =>
                             (runningOutput.LastOrDefault() == value
                                      ? runningOutput
                                      : runningOutput.Append(value)));

预先假定存在类似于以下的扩展方法:

static class Ex
{
    public static List<T> Append<T>(this List<T> source, T value)
    {
        return new List<T>(source) { value };
    }
}

根据您的需要提供您自己的验证。

答案 7 :(得分:0)

像这样你不需要新的物体。

public static void RemoveConsecutiveDuplicates<T>(this List<T> collection)
{
    for (int i = 0; i < collection.Count - 1; i++)
    {
        if (collection[i].Equals(collection[i + 1]))
        {
            collection.RemoveAt(i);
            i--;
        }
    }
}

var collection = new [] { 2, 7, 7, 7, 2, 6, 4 }.ToList();
collection.RemoveConsecutiveDuplicates();

答案 8 :(得分:0)

我认为这是使用Linq最简单的方法:

colors.Where((color, i) => i == 0 || color != colors[i - 1]);

您可以在C#Interactive中尝试它:

> var colors = new[] { "red", "red", "blue", "green", "green", "red", "red", "yellow", "white", "white", "red", "white", "white" };
> colors.Where((color, i) => i == 0 || color != colors[i - 1])
WhereIterator { "red", "blue", "green", "red", "yellow", "white", "red", "white" }

这里的技巧是使用Where()重载,该重载接受带有索引的谓词,然后与原始数组中的前一项进行比较。

答案 9 :(得分:0)

采用@Simon Bartlett的简洁方法并加以改进,您也可以通用地执行此操作。

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
    var returnList = new List<T>();

    foreach (var item in iterable)
    {
        if (returnList.Count == 0 || !returnList.Last().Equals(item))
            returnList.Add(item);
    }

    return returnList;
}

答案 10 :(得分:0)

这是我的建议。它与@AlexJ的answer相似,只是增加了一个IEqualityComparer参数,该参数允许自定义相等性检查。我还删除了参数检查和实现之间的其他正确分隔,因为该解决方案并非旨在达到库级的质量。至于名字,我采用了@AntonSemenov的answer中的ExcludeConsecutiveDuplicates

public static IEnumerable<TSource> ExcludeConsecutiveDuplicates<TSource>(
    this IEnumerable<TSource> source, IEqualityComparer<TSource> comparer = null)
{
    if (source == null) throw new ArgumentNullException(nameof(source));
    comparer = comparer ?? EqualityComparer<TSource>.Default;
    bool isFirst = true;
    TSource last = default;
    foreach (var item in source)
    {
        if (isFirst || !comparer.Equals(item, last)) yield return item;
        isFirst = false;
        last = item;
    }
}

用法示例:

var source = new string[]
{
    "Red", "red", "blue", "green", "green", "red", "red", "yellow",
    "WHITE", "white", "red", "white", "white"
};
var result = source.ExcludeConsecutiveDuplicates(StringComparer.OrdinalIgnoreCase);
Console.WriteLine($"Result: {String.Join(", ", result)}");

输出:

Result: Red, blue, green, red, yellow, WHITE, red, white

accepted answer相比,此解决方案的优点在于,它不需要IList<T>类型的源就可以提高效率。