Устранить последовательные дубликаты элементов списка - PullRequest
43 голосов
/ 20 апреля 2011

Есть ли "хороший" способ устранения последовательных дубликатов элементов списка?

Пример:

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

должно стать

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

- под «хорошим» я подразумеваю наиболее читаемым и понятным для нового пользователя и быстрое выполнение:)

Ответы [ 9 ]

61 голосов
/ 20 апреля 2011

Простое и очень удобочитаемое решение:

List<string> results = new List<string>();
foreach (var element in array)
{
    if(results.Count == 0 || results.Last() != element)
        results.Add(element);
}
19 голосов
/ 20 апреля 2011

Вы можете бросить свой собственный стиль 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()).Если у вас нет этого требования и вы просто хотите работать с массивами, что-то вроде решения Саймона Бартлетта может быть немного более производительным.

Для получения дополнительной информации о том, почему это должны быть два метода, см. здесь

8 голосов
/ 20 апреля 2011

Вы можете создать простой универсальный метод для этой цели, как показано ниже:

[РЕДАКТИРОВАТЬ 2] (большое спасибо Эрику Липперту)

    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;
    }
5 голосов
/ 20 апреля 2011

Вы можете сделать это в 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);
}
1 голос
/ 06 ноября 2018

Я думаю, что это самое простое, что можно получить с помощью Linq:

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

Вы можете попробовать это в C # Интерактив:

> 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 (), которая принимает предикат с индексом, а затем сравнивать с предыдущим элементом в исходном массиве.

1 голос
/ 20 апреля 2011

Попробуйте это:

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
1 голос
/ 20 апреля 2011

Разрешение:

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: отредактированный код, чтобы он работал на «белом», «белом», «белом», «белом»

0 голосов
/ 24 июня 2017

Как этот, вам не нужен новый объект.

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();
0 голосов
/ 20 апреля 2011

Функциональный подход:

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

Предоставьте свою собственную проверку, если считаете, что это необходимо.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...