Skip to content

Add slicing of sequences via System.Range #748

Open
@atifaziz

Description

@atifaziz

I propose to add a new Elements extension that accepts System.Range and which will allow usage of the range operator .. in C# to succinctly express slicing with start and end offsets.

We already have Slice, which is why I propose to call this extension Elements. An overload of Slice would be confusing since it takes a count as the second argument as opposed to an index.

Prototype

public static IEnumerable<T> Elements<T>(this IEnumerable<T> source, Range range) =>
    ((range.Start.Value, range.Start.IsFromEnd), (range.End.Value, range.End.IsFromEnd)) switch
    {
        ((0, false), (0, true)) => source,
        ((var rs, false), (0, true)) => source.Skip(rs),
        ((0, false), (var re, true)) => source.SkipLast(re),
        ((var rs, true), (0, true)) => source.TakeLast(rs),
        ((var rs, false), (var re, false)) =>
            source.Index()
                  .SkipWhile(e => e.Key < rs)
                  .TakeWhile(e => e.Key < re)
                  .Select(e => e.Value),
        ((var rs, true), (var re, true)) =>
            source.TakeLast(rs)
                  .Take(rs - re),
        ((var rs, true), (var re, false)) =>
            source.Index()
                  .TakeLast(rs)
                  .TakeWhile(e => e.Key < re)
                  .Select(e => e.Value),
        ((var rs, false), (var re, true)) =>
            source.Index()
                  .CountDown(re, (e, cd) => cd is null ? (true, e) : (false, e))
                  .TakeWhile(e => e is (true, _))
                  .Choose(e => e)
                  .Skip(rs)
                  .Select(e => e.Value)
    };

Examples

var seq = Enumerable.Range(0, 10);

var q =
    from r in new[]
    {
        ..,
        5..,
        ..5,
        3..7,
        ..^3,
        ^3..,
        ^8..^2,
        ^8..6,
        2..^2,
        ..^20,
        20..,
    }
    select $"{r,6} = [{seq.Elements(r).ToDelimitedString(", ")}]";

foreach (var e in q)
    Console.WriteLine(e);

Output:

 0..^0 = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
 5..^0 = [5, 6, 7, 8, 9]
  0..5 = [0, 1, 2, 3, 4]
  3..7 = [3, 4, 5, 6]
 0..^3 = [0, 1, 2, 3, 4, 5, 6]
^3..^0 = [7, 8, 9]
^8..^2 = [2, 3, 4, 5, 6, 7]
 ^8..6 = [2, 3, 4, 5]
 2..^2 = [2, 3, 4, 5, 6, 7]
0..^20 = []
20..^0 = []

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions