Ответ 1
Простое и очень читаемое решение:
List<string> results = new List<string>();
foreach (var element in array)
{
if(results.Count == 0 || results.Last() != element)
results.Add(element);
}
Есть ли "хороший" способ устранения последовательных дубликатов элементов списка?
Пример:
["red"; "red"; "blue"; "green"; "green"; "red"; "red"; "yellow"; "white"; "white"; "red"; "white"; "white"]
должен стать
["red"; "blue"; "green"; "red"; "yellow"; "white"; "red"; "white"]
- "nice" я имею в виду наиболее читаемый и понятный для нового пользователя и быстрое выполнение:)
Простое и очень читаемое решение:
List<string> results = new List<string>();
foreach (var element in array)
{
if(results.Count == 0 || results.Last() != element)
results.Add(element);
}
Вы можете перевернуть свой собственный, linq-стиль.
// For completeness, this is two methods to ensure that the null check
// is done eagerly while the loop is done lazily. If that 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()
). Если у вас нет этого требования, и вы просто хотите работать с массивами, что-то вроде решения Саймона Бартлетта может быть немного более эффективным.
Для получения дополнительной информации о том, почему это должно быть два метода, см. here
Вы можете создать простой общий метод для этой цели, например ниже:
[EDIT 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;
}
Вы можете сделать это в 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);
}
Разрешение:
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: Отредактированный код, поэтому он работает на "белый", "белый", "белый", "белый"
Попробуйте следующее:
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
Функциональный подход:
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 };
}
}
Поставьте свою собственную проверку, если вы считаете необходимым.
Подобно этому вам не нужен новый объект.
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();