3 votes

Comment fusionner plusieurs valeurs consécutives dans une liste ?

Existe-t-il une fonction permettant de supprimer les valeurs conséquentes (c.-à-d. 14, 14 -> 14 , 12, 12 -> 12 ) ?

La liste suivante ( [12, 14, 14, 12, 12, 14] ):

List<string> foo = new List<string> { 12, 14, 14, 12, 12, 14 };

à la liste [12, 14, 12, 14] ?

5voto

fubo Points 647

Approche avec foreach

public static IEnumerable<T> DistinctByPrevious<T>(List<T> source)
{
    if (source != null && source.Any())
    {
        T prev = source.First();
        yield return prev;
        foreach (T item in source.Skip(1))
        {
            if (!EqualityComparer<T>.Default.Equals(item, prev))
            {
                yield return item;
            }
            prev = item;
        }
    }
}

4voto

Dmitry Bychenko Points 17719

Linq sans bibliothèques supplémentaires, mais avec les effets secondaires est un rapide et sale ( prior L'effet secondaire est laid) solution :

  List<string> foo = new List<string> { "12", "14", "14", "12", "12", "14" };

  string prior = null;

  List<string> result = foo
    .Where((v, i) => i == 0 || v != prior)
    .Select(v => prior = v)
    .ToList();

En cas général il est possible que vous souhaitiez mettre en œuvre un méthode d'extension :

  public static partial class EnumerableExtensions {  
    public static IEnumerable<T> DistinctSuccessive<T>(
      this IEnumerable<T> source, 
           IEqualityComparer<T> comparer = null) {
      // public method arguments validation
      if (null == source)
        throw new ArgumentNullException(nameof(source));

      // equals: either default or custom one 
      Func<T, T, bool> equals = (left, right) => null == comparer 
        ? object.Equals(left, right) 
        : comparer.Equals(left, right);

      bool first = true;
      T prior = default(T);

      foreach (var item in source) {
        if (first || !equals(item, prior))
          yield return item;

        first = false;
        prior = item;
      }
    }
  }

Dans ce cas

  List<string> result = foo
    .DistinctSuccessive()
    .ToList();

-1voto

vasily.sib Points 2417

Personnellement, je préfère la réponse de @fubo, mais c'est juste pour montrer qu'il y a plus de variantes :

var data = new[] { 12, 14, 14, 12, 12, 14 };
var result = data.Aggregate(new List<int>(), (a, e) => { if (a.FirstOrDefault() != e) a.Insert(0, e); return a; });
result.Reverse(); // we builded a list in a back order, so reverse it!

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X