简体   繁体   中英

Unique in order C#

I have some trouble with executing an exercise from CodeWars. I made it in another compilator and everything works as it has to be but in CodeWars there are IEnumerable errors and I have no idea how to deal with them.

So, here is the exercise:

Implement the function unique_in_order which takes as argument a sequence and returns a list of items without any elements with the same value next to each other and preserving the original order of elements.

For example:

 uniqueInOrder("AAAABBBCCDAABBB") == {'A', 'B', 'C', 'D', 'A', 'B'} uniqueInOrder("ABBCcAD") == {'A', 'B', 'C', 'c', 'A', 'D'} uniqueInOrder([1,2,2,3,3]) == {1,2,3}

My solution:

using System.Collections.Generic;

public static class Kata {
    public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) {

    var first = iterable[0];
    
    var uniques = new List<char>();

    uniques.Add(first);
    
    foreach(var item in iterable)
    {
        if (item == first)
        {
            continue;
        }
        first = item;
        uniques.Add(first);
    }

    var result = string.Join("", uniques);

   return result;
  }
}

Errors I get:

src/Solution.cs(8,17): error CS0021: Cannot apply indexing with [] to an expression of type 'IEnumerable<T>'
src/Solution.cs(26,12): error CS0029: Cannot implicitly convert type 'string' to 'System.Collections.Generic.IEnumerable<T>'

Why don't you use yield return keyword? They're handy.

class Program
{
    public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> sequence)
    {
        T prev = default!;
        bool hasPrev = false;

        foreach (T item in sequence)
        {
            if ((!hasPrev && (hasPrev = true)) || !EqualityComparer<T>.Default.Equals(item, prev))
            {
                yield return item;
            }

            prev = item;
        }
    }

    static void Main(string[] args)
    {
        Console.WriteLine(new string(UniqueInOrder("AAAABBBCCDAABBB").ToArray()));
        Console.WriteLine(new string(UniqueInOrder("ABBCcAD").ToArray()));
    }
}

Firstly, exchange var first = iterable[0]; with var first = iterable.First() .
You can't use indexing on IEnumerable .

Secondly you are using list of chars List<char>(); to store type T . Use List<T> .
You can't store general type as specific.

Thirdly, why you are using String.Join() at the end, why not just return uniques?
List is also an IEnumerable .

You were close to a solution. Let's run through some errors:

In this statement: var first = iterable[0]; you can't access an IEnumerable item via indexing. IEnumerables aren't really lists or collections. I can expand on that if you'd like.

You could access it through:

var first = iterable.First();

In this statement: var uniques = new List<char>(); , you're creating a list of char to hold the itens of your IEnumerable, although the itens are of generic type T . The correct form is:

var uniques = new List<T>();

In the line if (item == first) , you can't compare two unconstrained generic types using == .

You can either use item.Equals(first) or EqualityComparer<T>.Default.Equals(item, first) .

Lastly, you're transforming your list in a string and returning it. Although the return type of your method is not a string, but rather an IEnumerable<T> .

Instead of

 var result = string.Join("", uniques);

 return result;

You can get rid of result , and return your list:

return uniques;

With these fixes, your code becomes:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) 
{
    var first = iterable.First();
    
    var uniques = new List<T>();

    uniques.Add(first);
    
    foreach(var item in iterable)
    {
        if (item.Equals(first))
        {
            continue;
        }
        first = item;
        uniques.Add(item);
    }

    return uniques;
}

Which already works. However, this code could be simplified by removing the assignment of the first variable and integrating it to a more general case. You could also remove the uniques list and yield each item at a time.

My proposed final solution is as follows:

public static IEnumerable<T> UniqueInOrder<T>(IEnumerable<T> iterable) 
{
    var current = default(T);
    
    foreach(var item in iterable)
    {
        if (item.Equals(current))
            continue;
            
        current = item;
        
        yield return item;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM