-1

What would be an efficient way to replace contiguous identical values in a list elements by another given value, but only if the the contiguous sequence runs for more than a certain number of elements (eg : more or equals to 5)

Example:

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

should become:

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

Any idea?

Yahia
  • 805
  • 7
  • 25
  • Do *you* have any idea? – Ňɏssa Pøngjǣrdenlarp Jun 24 '19 at 23:18
  • 2
    *efficient way* is subjective, do you mean speed, memory, lines of code, readability? either way *O(n)* `for` loop, with a first index, last value, and duplicate counter. When reaching a threshold it overwrites the given word up to current index and going forward. There is no need to over think this.. You could get fancy with *Linq* however i think that would be less intuitive – TheGeneral Jun 24 '19 at 23:19
  • 1
    MoreLinq's `GroupAdjacent` is one place you could start. – mjwills Jun 24 '19 at 23:20
  • How about enumerating the list, keeping track of the previous value, as well as the index of the first identical value? – Theodor Zoulias Jun 25 '19 at 06:29

1 Answers1

3

As said in the comments, using GroupAdjacent to group contiguous duplicates using the nuget package MoreLinq is an option:

var strings = new List<string> { "red", "red", "blue", "green", "green", "red", "red", "red", "red", "red", "red", "yellow", "white", "white", "red", "white", "white" };

var result = strings
    .GroupAdjacent(x => x)
    .SelectMany(grp => (grp.Count() >= 5) ?
                grp.Select(x => "ignore") : 
                grp);

Console.WriteLine("{ " + string.Join(", ", result) + " }");

Result:

{ red, red, blue, green, green, ignore, ignore, ignore, ignore, ignore, ignore, yellow, white, white, red, white, white }

The above also uses Enumerable.SelectMany to flatten the grouped IEnumerable<IEnumerable<string>> sequence into a IEnumerable<string>, and then a ternary operator to decide if the group should be completely replaced by "ignore" with Enumerable.Select if the group length from Enumerable.Countis greater or equal to 5, or left as is.

RoadRunner
  • 25,803
  • 6
  • 42
  • 75