I am probably doing something wrong but I'm trying to do this Kata on Codewars
This is my current code below.
public static class Kata
{
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> arr)
{
Type t = typeof(T);
if (t == typeof(string))
return (IEnumerable<T>)String.Join("",arr.Distinct()).AsEnumerable();
return arr.Distinct().ToArray();
}
}
The unit tests for this kata are expecting an input of "AAAABBBCCDAABBB" to be returned as "ABCDAB".
My code above is failing due to this error
Expected is <System.String>, actual is <System.Char[6]>
If I try to return a string I get this error: error CS0029: Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable<T>'
I'm lost as how I can return the expected string if I can't return a string (and a char array fails)
Thanks
CodePudding user response:
You can implement it like this (since you've used <T>
let implement general case solution with custom comparer
):
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> source,
IEqualityComparer<T> comparer = null) {
if (null == source)
throw new ArgumentNullException(nameof(source));
comparer ??= EqualityComparer<T>.Default;
bool first = true;
T prior = default; // default: let compiler be happy
foreach (T item in source)
if (first || !comparer.Equals(item, prior)) {
prior = item;
first = false;
yield return item;
}
}
Here we just check if current item
is equal to prior
.
Demo:
string source = "AAAABBBCCDAABBB";
string result = string.Concat(UniqueInOrder(source));
Console.Write(result);
Outcome:
ABCDAB
Edit: Please, note that Distinct()
in the
arr.Distinct()
removes duplicates in the entire arr
, that's why you'll get only 4 distinct characters:
AAAABBBCCDAABBB -> ABCD
Distinct()
In the given problem we have a weaker condition: current item must not be equal to prior.
CodePudding user response:
This should do it:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
using var e = iterable.GetEnumerator();
bool EnumeratorActive = e.MoveNext(); //start iterating
while (EnumeratorActive)
{
// set and yield the current value
T cur = e.Current;
yield return cur;
// keep advancing while the iterator is active and additional values match the current val
while(cur.Equals(e.Current) && (EnumeratorActive = e.MoveNext()))
{} //empty body intentional
}
}
It uses a pattern of nested while loops called Control/Break that still runs in linear time (because only the inner loop advances).
Here's a reduced version without the extra explainers:
public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable)
{
using var e = iterable.GetEnumerator();
bool EnumeratorActive = e.MoveNext();
while (EnumeratorActive)
{
T cur = e.Current;
yield return cur;
while(cur.Equals(e.Current) && (EnumeratorActive = e.MoveNext()));
}
}