views:

109

answers:

1

I'm trying to normalize arbitrary chains of .Skip() and .Take() calls to a single .Skip() call followed by an optional single .Take() call.

Here are some examples of expected results, but I'm not sure if these are correct:

.Skip(5)                        => .Skip(5)
.Take(7)                        => .Skip(0).Take(7)

.Skip(5).Skip(7)                => .Skip(12)
.Skip(5).Take(7)                => .Skip(5).Take(7)
.Take(7).Skip(5)                => .Skip(5).Take(2)
.Take(5).Take(7)                => .Skip(0).Take(5)

.Skip(5).Skip(7).Skip(11)       => .Skip(23)
.Skip(5).Skip(7).Take(11)       => .Skip(12).Take(11)
.Skip(5).Take(7).Skip(3)        => .Skip(8).Take(4)
.Skip(5).Take(7).Take(3)        => .Skip(5).Take(4)
.Take(11).Skip(5).Skip(3)       => .Skip(8).Take(3)
.Take(11).Skip(5).Take(7)       => .Skip(5).Take(6)
.Take(11).Take(5).Skip(3)       => .Skip(3).Take(2)
.Take(11).Take(5).Take(3)       => .Skip(0).Take(3)

Can anyone confirm these are the correct results to be expected?


Here is the basic algorithm that I derived from the examples:

class Foo
{
    private int skip;
    private int? take;

    public Foo Skip(int value)
    {
        if (value < 0)
            value = 0;

        this.skip += value;

        if (this.take.HasValue)
            this.take -= value;

        return this;
    }

    public Foo Take(int value)
    {
        if (value < 0)
            value = 0;

        if (!this.take.HasValue || value < this.take)
            this.take = value;

        return this;
    }
}

Any idea how I can confirm if this is the correct algorithm?

+4  A: 

This is a perfect scenario for TDD. Given that you have defined your spec above, this should be cake to implement as a series of just a couple of tests.

"Correct" is fairly subjective, but those examples seem sane.

Also, I would normalize out the .Skip(0) calls.

Make sure you define your edge cases clearly. For example,

.Take(11).Skip(12).Take(1)

should probably be normalized into a .Take(0)


Edit:

The official definition of skip:

Bypasses a specified number of elements in a sequence and then returns the remaining elements.

And take:

Returns a specified number of contiguous elements from the start of a sequence.

Based on your examples, I think that your test cases are properly following the spec.

John Gietzen
The problem is not so much implementing my own specification, but finding the "correct" specification, since I'm not developing my own query framework but plug into LINQ. Is there any official documentation how LINQ Skip/Take implementations should behave?
dtb
Right, the documentation is not really explicit on how chains should be evaluated, but from those specifications I agree my test cases (that I derived from intuition) look sane. I guess I'll have to make up more test cases to catch all edge cases and update the algorithm accordingly.
dtb