Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Alternative to IEnumerable<T>.Skip(1).Take(1).Single()

I am having a difficult time with a seemingly easy and embarrassing problem. All I want is the next element in an IEnumberable without using Skip(1).Take(1).Single(). This example illustrates the basic problem.

private char _nextChar;
private IEnumerable<char> getAlphabet()
{
    yield return 'A';
    yield return 'B';
    yield return 'C';
}
public void sortAlphabet()
{
     foreach (char alpha in getAlphabet())
     {
         switch (alpha)
         {
             case 'A':  //When A pops up, I want to get the next element, ie 'B'
                 _nextChar = getAlphabet().Skip(1).Take(1).Single();
                 break;
             case 'B': //When B pops up, I want 'C' etc
                 _nextChar = getAlphabet().Skip(1).Take(1).Single();
                 break;
         }
     }
}

Other than being ugly, this example works. But let's say that the IEnumerable contained 2 million elements, then the LINQ statement makes the program execute unbearably slow. What I want is simple. I just want the next element in an IEnumberable<>. All my problems would be solved if there was a function like:

_nextChar = getAlphabet().moveNext() //or getNext()

It is much preferred if the solution keeps the same structure/layout/functionality of the example however, I am flexible. My program is a file parser, and among the 2 million lines of text are some keys like "money=324" where "money" and "324" are neighbor elements in the IEnumberable and when the parser comes across "money" I want "324". (who doesn't? :D Sorry for bad pun.)

like image 536
Nick Babcock Avatar asked Aug 28 '10 15:08

Nick Babcock


People also ask

How do you skip a method in C#?

Use the Skip() method in C# to skip number of elements in an array.

What is IEnumerable T in C#?

IEnumerable. IEnumerable<T> contains a single method that you must implement when implementing this interface; GetEnumerator, which returns an IEnumerator<T> object. The returned IEnumerator<T> provides the ability to iterate through the collection by exposing a Current property.

What is skip in Linq C#?

C# Linq Skip() MethodSkip elements and return the remaining elements using the Skip() method. The following is an array. int[] marks = { 80, 55, 79, 99 }; Now, let us skip 2 elements using Lambda Expressions, but this is done after arranging the elements in descending order.

How do you use take and skip in Linq?

The Take operator is used to return a given number of elements from an array and the Skip operator skips over a specified number of elements from an array. Skip, skips elements up to a specified position starting from the first element in a sequence.


1 Answers

All my problems would be solved if there was a function like:

_nextChar = getAlphabet().moveNext() //or getNext()

There is a function exactly like that. It just belongs to IEnumerator<T>, not IEnumerable<T>!

private char _nextChar;
private IEnumerable<char> getAlphabet()
{
    yield return 'A';
    yield return 'B';
    yield return 'C';
}

public void sortAlphabet()
{
    using (var enumerator = getAlphabet().GetEnumerator())
    {
        while (enumerator.MoveNext())
        {
            char alpha = enumerator.Current;
            switch (alpha)
            {
                case 'A':
                    if (enumerator.MoveNext())
                    {
                        _nextChar = enumerator.Currrent;
                    }
                    else
                    {
                        // You decide what to do in this case.
                    }
                    break;
                case 'B':
                    // etc.
                    break;
            }
        }
    }
}

Here's a question for you, though. Is it necessary that this code use an IEnumerable<char>, rather than an IList<char>? I ask because, as if this weren't obvious, the code would be much simpler if you had random access to the items returned by getAlphabet by index (and if someone is tempted to point out that you can do this with ElementAt, please, just get that idea out of your head right now).

I mean, consider what the code would look like in this case:

private char _nextChar;
private IList<char> getAlphabet()
{
    return Array.AsReadOnly(new[] { 'A', 'B', 'C' });
}

public void sortAlphabet()
{
    IList<char> alphabet = getAlphabet();
    for (int i = 0; i < alphabet.Count - 1; ++i)
    {
        char alpha = alphabet[i];
        switch (alpha)
        {
            case 'A':
                _nextChar = alphabet[i + 1];
                break;
            case 'B':
                // etc.
                break;
        }
    }
}

Isn't that much easier?

like image 59
Dan Tao Avatar answered Sep 30 '22 17:09

Dan Tao