Question

The TakeWhile extension method has the following comment in its tooltip: "the element's index is used in the logic of the predicate function". Note that this tooltip is not visible in the normal tooltip but only in the tooltip of the list of intellisense for the lists members of the variable sortedDictionary.

That's exactly what is was looking for in combination with a SortedDictionary.

var first = sortedDictionary.First(kv => kv.Key.ToString().StartsWith(searchkey));
var last= sortedDictionary.Last(kv => kv.Key.ToString().StartsWith(searchkey));
var range = sortedDictionary.TakeWhile(kv => kv.Key.ToString().StartsWith(searchkey));

The items first and last are found and correct, however my collection range is empty.
What is wrong here? I expected a range with all items between first and last including them.

I could still find the range using first and last but TakeWhile uses the index while First and Last apparantly don't.

EDIT: "using the index" turns out to have nothing to do with sorting but you can use the index in the query. E.g. when I replace SortedDictionary with SortedList I can do:

int ix1 = sortedList.IndexOfKey(first.Key);
int ix2 = sortedList.IndexOfKey(last.Key);
var range = sortedList.SkipWhile((x, i) => i < ix1).TakeWhile((x, i) => i <= ix2);

Also with SortedDictionary I can do:

var range = sortedList.SkipWhile(x => !x.Key.ToString().StartsWith(searchkey))
                      .TakeWhile(x => x.Key.ToString().StartsWith(searchkey));

I will have to test which method is faster and also have to test the Where query.

Was it helpful?

Solution

If the first element in your sequence does not match your predicate, then the TakeWhile method will exit:

Returns elements from a sequence as long as a specified condition is true

The First method will take the first element that matches your predicate:

Returns the first element in a sequence that satisfies a specified condition

Opposite of the First method, the Last method will take the last element that matches your predicate:

Returns the last element of a sequence that satisfies a specified condition

I'm guessing that the TakeWhile is exiting early because their are no elements matching the condition when the iteration begins.

If you want the range of elements between the first and last element from your example (including both the first and last item), then try this:

var range = sortedDictionary.SkipWhile( x => !x.Equals( first ) )
  .TakeWhile( x => !x.Equals( last ) )
  .Concat( new SortedDictionary<string, string> { { last.Key, last.Value } } );

Or you could just not over-think this like me and use a simpler approach using the Where method as in Jeff's example.

OTHER TIPS

TakeWhile() will take items starting from the beginning of the sequence as long as they all satisfy the predicate. If the first item fails the predicate, the result is empty. The description you are talking about is from the overload that includes an index (which you aren't using).

Just filter items normally and it should yield the range you are expecting (due to the sorting).

var range = sortedDictionary.Where(kv => kv.Key.ToString().StartsWith(searchkey));

The tooltip you read is for an overload whose predicate has a Int32 as a parameter MSDN Link

Would you mind posting some code as to see why it's returning an empty range?. The following code works as expected (I copy/pasted your code).

        var sortedDictionary = new SortedDictionary<string, string>();
        var searchkey = "test";
        sortedDictionary.Add("test1", "value");
        sortedDictionary.Add("test2", "value");
        sortedDictionary.Add("test3", "value");
        sortedDictionary.Add("test4", "value");

        var first = sortedDictionary.First(kv => kv.Key.ToString().StartsWith(searchkey));
        var last = sortedDictionary.Last(kv => kv.Key.ToString().StartsWith(searchkey));
        var range = sortedDictionary.TakeWhile(
            kv => kv.Key.ToString().StartsWith(searchkey));
        foreach (var c in range)
        {
            Console.WriteLine(c);
        }
        Console.ReadKey();
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top