diff --git a/MoreLinq.Test/Enumerable.cs b/MoreLinq.Test/Enumerable.cs index a63220274..bb8267e61 100644 --- a/MoreLinq.Test/Enumerable.cs +++ b/MoreLinq.Test/Enumerable.cs @@ -45,6 +45,9 @@ public static bool Any(this IEnumerable source) => public static bool Any(this IEnumerable source, Func predicate) => LinqEnumerable.Any(source, predicate); + public static IEnumerable Append(this IEnumerable source, TSource element) => + LinqEnumerable.Append(source, element); + public static IEnumerable AsEnumerable(this IEnumerable source) => LinqEnumerable.AsEnumerable(source); diff --git a/MoreLinq.Test/SpillHeadTest.cs b/MoreLinq.Test/SpillHeadTest.cs new file mode 100644 index 000000000..0ff273690 --- /dev/null +++ b/MoreLinq.Test/SpillHeadTest.cs @@ -0,0 +1,200 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2020 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq.Test +{ + using System.Collections.Generic; + using System.Globalization; + using System.Text.RegularExpressions; + using NUnit.Framework; + using static FuncModule; + + [TestFixture] + public class SpillHeadTest + { + [Test] + public void RepeatHeadElementWithRest() + { + using var ts = TestingSequence.Of(5, 6, 7, 8, 9, 10); + var result = ts.SpillHead(); + + Assert.That(result, Is.EqualTo(new[] + { + (5, 6), (5, 7), (5, 8), (5, 9), (5, 10) + })); + } + + [Test] + public void HeadElementOnly() + { + using var ts = TestingSequence.Of("head"); + var result = ts.SpillHead(); + Assert.That(result, Is.Empty); + } + + [Test] + public void RepeatHeadElementsWithRest() + { + using var ts = TestingSequence.Of(5, 6, 7, 8, 9, 10); + var result = ts.SpillHead(2, hs => hs, (h, d) => (h[0], h[1], d)); + + Assert.That(result, Is.EqualTo(new[] + { + (5, 6, 7), (5, 6, 8), (5, 6, 9), (5, 6, 10) + })); + } + + [TestCase(0)] + [TestCase(1)] + [TestCase(2)] + [TestCase(3)] + public void InsufficientElementsPerHeadCount(int count) + { + using var ts = Enumerable.Repeat("head", count).AsTestingSequence(); + var result = ts.SpillHead(3, + BreakingFunc.Of, object>(), + BreakingFunc.Of()); + + Assert.That(result, Is.Empty); + } + + [Test] + public void PredicatedHeads() + { + using var ts = TestingSequence.Of("head1", "head2", "head3", + "foo", "bar", "baz"); + + var result = ts.SpillHead(h => Regex.IsMatch(h, "^head[0-9]$"), + hs => string.Join("|", hs), + (h, e) => new { Head = h, Data = e }); + + Assert.That(result, Is.EqualTo(new[] + { + new { Head = "head1|head2|head3", Data = "foo" }, + new { Head = "head1|head2|head3", Data = "bar" }, + new { Head = "head1|head2|head3", Data = "baz" }, + })); + } + + [Test] + public void CustomAccumulation() + { + using var ts = TestingSequence.Of("head1", "head2", "head3", + "foo", "bar", "baz"); + + var result = ts.SpillHead(h => Regex.IsMatch(h, "^head[0-9]$"), + () => [], + MoreEnumerable.Return, + (hs, h) => hs.Append(h), + hs => string.Join("|", hs), + (h, e) => new { Head = h, Data = e }); + + Assert.That(result, Is.EqualTo(new[] + { + new { Head = "head1|head2|head3", Data = "foo" }, + new { Head = "head1|head2|head3", Data = "bar" }, + new { Head = "head1|head2|head3", Data = "baz" }, + })); + } + + [Test] + public void NoneSatisfyHeadPredicate() + { + using var words = TestingSequence.Of("foo", "bar", "baz"); + var result = words.SpillHead(e => e == "head", + hs => hs.Count, + (hc, e) => new { HeadCount = hc, Data = e }); + + Assert.That(result, Is.EqualTo(new[] + { + new { HeadCount = 0, Data = "foo" }, + new { HeadCount = 0, Data = "bar" }, + new { HeadCount = 0, Data = "baz" }, + })); + } + + [Test] + public void Csv() + { + const string csv = @" + a,c,b + 1,3,2 + 4,6,5 + 7,9,8"; + + var rows = + from line in Regex.Split(csv.Trim(), @"\r?\n") + select line.Split(',').Select(f => f.Trim()).ToArray(); + + using var ts = rows.AsTestingSequence(); + var result = + ts.SpillHead( + h => MoreEnumerable.Return(h.Index() + .ToDictionary(e => e.Value, e => e.Key)) + .SelectMany(d => new[] { "a", "b", "c" }, + (d, n) => d[n]) + .Select(i => Func((string[] s) => s[i])) + .ToArray(), + (bs, r) => bs.Select(b => int.Parse(b(r), CultureInfo.InvariantCulture)) + .Fold((a, b, c) => new { A = a, B = b, C = c })); + + Assert.That(result, Is.EqualTo(new[] + { + new { A = 1, B = 2, C = 3 }, + new { A = 4, B = 5, C = 6 }, + new { A = 7, B = 8, C = 9 }, + })); + } + + [Test] + public void CsvWithColumnsInCommentLines() + { + const string csv = @" + ; a = Column A + ; b = Column B + ; c = Column C + 1,2,3 + 4,5,6 + 7,8,9"; + + using var ts = Regex.Split(csv.Trim(), @"\r?\n") + .Select(line => line.Trim()) + .AsTestingSequence(); + + var result = + from e in + ts.SpillHead(h => Regex.Match(h, @"^;\s*(\w+)") is var m & m.Success ? (true, m.Groups[1].Value) : default, + h => MoreEnumerable.Return(h.Index() + .ToDictionary(e => e.Value, e => e.Key)) + .SelectMany(d => new[] { "a", "b", "c" }, + (d, n) => d[n]) + .Select(i => Func((string[] s) => s[i])) + .ToArray(), + (bs, r) => new { Bindings = bs, Fields = r.Split(',') }) + select e.Bindings + .Select(b => int.Parse(b(e.Fields), CultureInfo.InvariantCulture)) + .Fold((a, b, c) => new { A = a, B = b, C = c }); + + Assert.That(result, Is.EqualTo(new[] + { + new { A = 1, B = 2, C = 3 }, + new { A = 4, B = 5, C = 6 }, + new { A = 7, B = 8, C = 9 }, + })); + } + } +} diff --git a/MoreLinq/Extensions.g.cs b/MoreLinq/Extensions.g.cs index 81e42062e..ddb18439e 100644 --- a/MoreLinq/Extensions.g.cs +++ b/MoreLinq/Extensions.g.cs @@ -5589,6 +5589,474 @@ public static IEnumerable SortedMerge(this IEnumerableSpillHead extension. + + [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] + public static partial class SpillHeadExtension + { + /// + /// Couples the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. + /// + /// Type of source sequence elements. + /// The source sequence. + /// + /// A sequence with the head element coupled together with the + /// remainder elements of the source sequence. + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable<(T Head, T Item)> + SpillHead(this IEnumerable source) => MoreEnumerable. SpillHead(source); + + /// + /// Projects the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. An additional argument + /// specifies a function that receives an element of sequence + /// together with the first/head element and returns a projection. + /// + /// Type of source sequence elements. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that projects a result + /// given the head and one of the remainder elements. + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func resultSelector) => MoreEnumerable. SpillHead(source, resultSelector); + + /// + /// Projects the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to project the head as well as the elements + /// of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that projects an + /// intermediate head representation. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to project the head as well as the elements of the + /// resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Count head elements to collect. + /// Function that projects an + /// intermediate head representation given a list of exactly + /// head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + int count, + Func, THead> headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, count, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to project the head as well as the elements (along with + /// their index) of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Count head elements to collect. + /// Function that projects an + /// intermediate head representation given a list of exactly + /// head elements. + /// + /// Function that projects a result given + /// the head projection returned by + /// and one of the remainder elements along with its zero-based index + /// (where zero is the first non-head element). + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + int count, + Func, THead> headerSelector, + Func resultSelector) => MoreEnumerable. SpillHead(source, count, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to delineate header elements, project the header + /// elements as well as the elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is at the head. + /// Function that projects an + /// intermediate head representation given a list of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func, THead> headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, predicate, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements (possibly based + /// on their index), project the header elements as well as the + /// elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is at the head. + /// Function that projects an + /// intermediate head representation given a list of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func, THead> headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, predicate, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements, + /// project the header elements as well as the elements of the + /// resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is a match for a head. + /// Function that projects an + /// intermediate head representation given a list of head matches. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func, THead> headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, matcher, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements + /// (possibly based on their index), project the header elements + /// as well as the elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is a match for a head. + /// Function that projects an + /// intermediate head representation given a list of head matches. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func, THead> headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, matcher, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements, fold and + /// project the header elements as well as project elements of + /// the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is at the head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, predicate, empty, seeder, accumulator, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements (possibly based on + /// their index), fold and project the header elements as well as + /// project elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is at the head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, predicate, empty, seeder, accumulator, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements, + /// fold and project the header elements as well as project + /// elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is a match for a head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, matcher, empty, seeder, accumulator, headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements + /// (possibly based on their index), fold and project the header + /// elements as well as project elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is a match for a head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + => MoreEnumerable. SpillHead(source, matcher, empty, seeder, accumulator, headerSelector, resultSelector); + + } + /// Split extension. [GeneratedCode("MoreLinq.ExtensionsGenerator", "1.0.0.0")] diff --git a/MoreLinq/MoreLinq.csproj b/MoreLinq/MoreLinq.csproj index 1ec1d5123..bd87a1c34 100644 --- a/MoreLinq/MoreLinq.csproj +++ b/MoreLinq/MoreLinq.csproj @@ -89,6 +89,7 @@ - SkipUntil - Slice - SortedMerge + - SpillHead - Split - StartsWith - Subsets diff --git a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt index 7dc5c5811..1caec2848 100644 --- a/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net6.0/PublicAPI.Unshipped.txt @@ -1 +1,28 @@ #nullable enable +MoreLinq.Extensions.SpillHeadExtension +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! diff --git a/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt index 7dc5c5811..1caec2848 100644 --- a/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/net8.0/PublicAPI.Unshipped.txt @@ -1 +1,28 @@ #nullable enable +MoreLinq.Extensions.SpillHeadExtension +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! diff --git a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt index 7dc5c5811..1caec2848 100644 --- a/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.0/PublicAPI.Unshipped.txt @@ -1 +1,28 @@ #nullable enable +MoreLinq.Extensions.SpillHeadExtension +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! diff --git a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt index 7dc5c5811..1caec2848 100644 --- a/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt +++ b/MoreLinq/PublicAPI/netstandard2.1/PublicAPI.Unshipped.txt @@ -1 +1,28 @@ #nullable enable +MoreLinq.Extensions.SpillHeadExtension +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.Extensions.SpillHeadExtension.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, int count, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func!, THead>! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! matcher, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source, System.Func! predicate, System.Func! empty, System.Func! seeder, System.Func! accumulator, System.Func! headerSelector, System.Func! resultSelector) -> System.Collections.Generic.IEnumerable! +static MoreLinq.MoreEnumerable.SpillHead(this System.Collections.Generic.IEnumerable! source) -> System.Collections.Generic.IEnumerable<(T Head, T Item)>! diff --git a/MoreLinq/SpillHead.cs b/MoreLinq/SpillHead.cs new file mode 100644 index 000000000..d80bb15ed --- /dev/null +++ b/MoreLinq/SpillHead.cs @@ -0,0 +1,616 @@ +#region License and Terms +// MoreLINQ - Extensions to LINQ to Objects +// Copyright (c) 2020 Atif Aziz. All rights reserved. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +#endregion + +namespace MoreLinq +{ + using System; + using System.Collections.Generic; + + partial class MoreEnumerable + { + /// + /// Couples the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. + /// + /// Type of source sequence elements. + /// The source sequence. + /// + /// A sequence with the head element coupled together with the + /// remainder elements of the source sequence. + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable<(T Head, T Item)> + SpillHead(this IEnumerable source) => + source.SpillHead(h => h, ValueTuple.Create); + + /// + /// Projects the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. An additional argument + /// specifies a function that receives an element of sequence + /// together with the first/head element and returns a projection. + /// + /// Type of source sequence elements. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that projects a result + /// given the head and one of the remainder elements. + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func resultSelector) => + source.SpillHead(h => h, resultSelector); + + /// + /// Projects the first/head element of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to project the head as well as the elements + /// of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that projects an + /// intermediate head representation. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((_, i) => i == 0, + () => throw new UnreachableException(), + h => h, (a, _) => a, + headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to project the head as well as the elements of the + /// resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Count head elements to collect. + /// Function that projects an + /// intermediate head representation given a list of exactly + /// head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + int count, + Func, THead> headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + // TODO validate count < 1? + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead(count, headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to project the head as well as the elements (along with + /// their index) of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Count head elements to collect. + /// Function that projects an + /// intermediate head representation given a list of exactly + /// head elements. + /// + /// Function that projects a result given + /// the head projection returned by + /// and one of the remainder elements along with its zero-based index + /// (where zero is the first non-head element). + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + int count, + Func, THead> headerSelector, + Func resultSelector) => + source.SpillHead((_, i) => i < count, + headerSelector, resultSelector); + + /// + /// Projects the head elements of the sequence exclusively with the + /// remainder elements of the sequence. Additional arguments specify + /// functions to delineate header elements, project the header + /// elements as well as the elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is at the head. + /// Function that projects an + /// intermediate head representation given a list of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func, THead> headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, _) => predicate(e), + headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements (possibly based + /// on their index), project the header elements as well as the + /// elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is at the head. + /// Function that projects an + /// intermediate head representation given a list of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func, THead> headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, i) => predicate(e, i) ? (true, e) : default, + headerSelector, resultSelector); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements, + /// project the header elements as well as the elements of the + /// resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is a match for a head. + /// Function that projects an + /// intermediate head representation given a list of head matches. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func, THead> headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (matcher == null) throw new ArgumentNullException(nameof(matcher)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, _) => matcher(e), + headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements + /// (possibly based on their index), project the header elements + /// as well as the elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is a match for a head. + /// Function that projects an + /// intermediate head representation given a list of head matches. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func, THead> headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (matcher == null) throw new ArgumentNullException(nameof(matcher)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead(matcher, + () => [], + h => new List { h }, + (a, h) => { a.Add(h); return a; }, + hs => headerSelector(hs ?? []), + resultSelector); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements, fold and + /// project the header elements as well as project elements of + /// the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is at the head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (empty == null) throw new ArgumentNullException(nameof(empty)); + if (seeder == null) throw new ArgumentNullException(nameof(seeder)); + if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, _) => predicate(e), + empty, seeder, accumulator, headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to delineate header elements (possibly based on + /// their index), fold and project the header elements as well as + /// project elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is at the head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func predicate, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (predicate == null) throw new ArgumentNullException(nameof(predicate)); + if (empty == null) throw new ArgumentNullException(nameof(empty)); + if (seeder == null) throw new ArgumentNullException(nameof(seeder)); + if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, i) => predicate(e, i) ? (true, e) : default, + empty, seeder, accumulator, headerSelector, resultSelector); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements, + /// fold and project the header elements as well as project + /// elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence is a match for a head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (matcher == null) throw new ArgumentNullException(nameof(matcher)); + if (empty == null) throw new ArgumentNullException(nameof(empty)); + if (seeder == null) throw new ArgumentNullException(nameof(seeder)); + if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return source.SpillHead((e, _) => matcher(e), + empty, seeder, accumulator, headerSelector, + (h, e, _) => resultSelector(h, e)); + } + + /// + /// Projects the head elements of the sequence exclusively with + /// the remainder elements of the sequence. Additional arguments + /// specify functions to choose and delineate header elements + /// (possibly based on their index), fold and project the header + /// elements as well as project elements of the resulting sequence. + /// + /// Type of source sequence elements. + /// Type of head match. + /// Type of head accumulator state. + /// Type of head projection. + /// + /// Type of elements of the returned sequence. + /// The source sequence. + /// Function that determines whether an + /// element of the source sequence (along with its zero-based index) + /// is a match for a head. + /// The empty state when head is absent. + /// Function that seeds the accumulation state + /// with the initial head element. + /// Function that folds subsequent head + /// elements into the state. + /// Function that projects a single + /// head representation given the accumulated state of head elements. + /// + /// Function that projects a result + /// given the head projection returned by + /// and one of the remainder elements along with its zero-based index. + /// + /// A sequence of elements returned by + /// . + /// + /// This operator uses deferred execution and streams its results. + /// + + public static IEnumerable + SpillHead( + this IEnumerable source, + Func matcher, + Func empty, + Func seeder, + Func accumulator, + Func headerSelector, + Func resultSelector) + { + if (source == null) throw new ArgumentNullException(nameof(source)); + if (matcher == null) throw new ArgumentNullException(nameof(matcher)); + if (empty == null) throw new ArgumentNullException(nameof(empty)); + if (seeder == null) throw new ArgumentNullException(nameof(seeder)); + if (accumulator == null) throw new ArgumentNullException(nameof(accumulator)); + if (headerSelector == null) throw new ArgumentNullException(nameof(headerSelector)); + if (resultSelector == null) throw new ArgumentNullException(nameof(resultSelector)); + + return _(); IEnumerable _() + { + using var e = source.GetEnumerator(); + if (!e.MoveNext()) + yield break; + var i = 0; + var (span, fm) = matcher(e.Current, i); + var state = span ? seeder(fm) : empty(); + if (span) + { + for (;;) + { + if (!e.MoveNext()) + yield break; + if (matcher(e.Current, ++i) is (true, var m)) + state = accumulator(state, m); + else + break; + } + } + var header = headerSelector(state); + state = default; // available for collection by GC + i = 0; + do { yield return resultSelector(header, e.Current, i++); } + while (e.MoveNext()); + } + } + } +} diff --git a/README.md b/README.md index 2a897f211..c1632842d 100644 --- a/README.md +++ b/README.md @@ -592,6 +592,19 @@ descending) into a single sequence that preserves that order. This method has 2 overloads. +### SpillHead + +Projects the head elements of a sequence exclusively with the remainder +elements of the sequence. Arguments of various overloads specify functions to +choose and delineate header elements (possibly based on their index), fold and +project the header elements as well as project elements of the resulting +sequence. + +This method has 13 overloads. + +Some of the simpler overloads enable pairing the one or more head elements +with the remainder elements of a sequence. + ### Split Splits the source sequence by a separator.