diff --git a/src/FSharpPlus/Data/NonEmptySeq.fs b/src/FSharpPlus/Data/NonEmptySeq.fs index 3a29e8524..d02dea965 100644 --- a/src/FSharpPlus/Data/NonEmptySeq.fs +++ b/src/FSharpPlus/Data/NonEmptySeq.fs @@ -77,6 +77,18 @@ module NonEmptySeq = let appendSeqBack (seq: _ seq) (source: _ NonEmptySeq) = Seq.append seq source |> unsafeOfSeq + /// Returns the average of the elements in the list. + /// The input list. + /// The resulting average. + let inline average (list: NonEmptySeq<'T>) = Seq.average list + + /// Returns the average of the elements generated by applying the function to each element of the list. + /// The function to transform the list elements into the type to be averaged. + /// The input list. + /// The resulting average. + let inline averageBy (projection: 'T -> ^U) (list: NonEmptySeq<'T>) = + Seq.averageBy projection list + /// Returns a sequence that corresponds to a cached version of the input sequence. /// This result sequence will have the same elements as the input sequence. The result /// can be enumerated multiple times. The input sequence will be enumerated at most @@ -103,7 +115,37 @@ module NonEmptySeq = /// /// The result sequence. let cache (source: _ NonEmptySeq) = Seq.cache source |> unsafeOfSeq + + /// Wraps a loosely-typed System.Collections sequence as a typed sequence. + /// The input sequence. + /// The result sequence. + /// Thrown when the input sequence is null. + let cast (source: _ NonEmptySeq) = Seq.cast source |> unsafeOfSeq + /// + /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). + /// + /// The function to be applied to the list elements. + /// The input sequence. + /// The resulting list comprising the values v where the chooser function returned Some(x). + let inline choose chooser (source: NonEmptySeq<'T>) = source |> Seq.choose chooser |> unsafeOfSeq + + /// + /// Applies a function to each element in a list and then returns a list of values v where the applied function returned Some(v). + /// + /// The function to be applied to the list elements. + /// The input sequence. + /// The resulting list comprising the values v where the chooser function returned Some(x). + let inline tryChoose chooser (source: NonEmptySeq<'T>) = source |> Seq.choose chooser |> List.ofSeq + + /// Divides the input list into lists (chunks) of size at most chunkSize. + /// Returns a new list containing the generated lists (chunks) as its elements. + /// The maximum size of each chunk. + /// The input sequence. + /// The sequence divided into chunks. + let inline chunkBySize chunkSize (source: NonEmptySeq<'T>) = + source |> Seq.chunkBySize chunkSize |> Seq.map unsafeOfSeq + /// Applies the given function to each element of the sequence and concatenates all the /// results. /// @@ -116,6 +158,26 @@ module NonEmptySeq = /// The result sequence. let collect (mapping: 'a -> '``#NonEmptySeq<'b>``) (source: NonEmptySeq<'a>) : NonEmptySeq<'b> when '``#NonEmptySeq<'b>`` :> NonEmptySeq<'b> = Seq.collect mapping source |> unsafeOfSeq + + /// For each element of the list, applies the given function. + /// Concatenates all the results and returns the combined list. + /// The function to transform each input element into a sublist to be concatenated. + /// The input sequence. + /// The concatenation of the transformed sublists. + let tryCollect (mapping: 'a -> #seq<'b>) (source: NonEmptySeq<'a>) : seq<'b> = + source |> Seq.collect mapping + + /// Compares two sequences using the given comparison function, element by element. + /// A function that takes an element from each sequence and returns an int. If it evaluates to a non-zero value iteration is stopped and that value is returned. + /// The first input sequence. + /// The second input sequence. + /// Returns the first non-zero result from the comparison function. + /// If the first sequence has a larger element, the return value is always positive. + /// If the second sequence has a larger element, the return value is always negative. + /// When the elements are equal in the two sequences, 1 is returned if the first sequence is longer, 0 is returned if they are equal in length, and -1 is returned when the second list is longer. + /// + let compareWith comparer (source1: NonEmptySeq<'T>) (source2: NonEmptySeq<'T>) = + Seq.compareWith comparer source1 source2 /// Combines the given enumeration-of-enumerations as a single concatenated /// enumeration. @@ -129,6 +191,24 @@ module NonEmptySeq = let concat (sources: NonEmptySeq<'``#NonEmptySeq<'a>``>) : NonEmptySeq<'a> when '``#NonEmptySeq<'a>`` :> NonEmptySeq<'a> = Seq.concat sources |> unsafeOfSeq + /// Returns a new list that contains the elements of each of the lists in order. + /// Returns None if all of the inner lists are empty. + /// The input list of lists. + /// The resulting concatenated list or None. + let inline tryConcat (sources: NonEmptySeq<#seq<'T>>) = sources |> Seq.concat |> unsafeOfSeq + + /// Tests if the sequence contains the specified element. + /// The value to locate in the input sequence. + /// The input sequence. + /// True if the input sequence contains the specified element; false otherwise. + let inline contains (value: 'T) (source: NonEmptySeq<'T>) = Seq.contains value source + + /// Applies a key-generating function to each element of a sequence and returns a sequence yielding unique keys and their number of occurrences in the original list. + /// A function transforming each item of the input sequence into a key to be compared against the others. + /// The input sequence. + /// The resulting sequence of unique keys and their number of occurrences. + let inline countBy (projection: 'T -> 'U) (source: NonEmptySeq<'T>) = Seq.countBy projection source + /// Returns a sequence that is built from the given delayed specification of a /// sequence. /// @@ -138,6 +218,164 @@ module NonEmptySeq = /// The generating function for the sequence. let delay (generator: unit -> NonEmptySeq<'a>) : NonEmptySeq<'a> = Seq.delay (fun () -> generator () :> _) |> unsafeOfSeq + /// Returns a sequence that contains no duplicate entries according to the generic hash and equality comparisons + /// on the keys returned by the given key-generating function. + /// If an element occurs multiple times in the sequence then the later occurrences are discarded. + /// The input sequence. + /// The resulting sequence without duplicates. + let distinct (source: NonEmptySeq<'T>) = source |> Seq.distinct |> unsafeOfSeq + + /// Returns a sequence that contains no duplicate entries according to the generic hash and equality comparisons on the keys returned by the given key-generating function. + /// If an element occurs multiple times in the sequence then the later occurrences are discarded. + /// A function transforming the sequence items into comparable keys. + /// The input sequence. + /// The resulting sequence. + let inline distinctBy (projection: 'T -> 'U) (source: NonEmptySeq<'T>) = Seq.distinctBy projection source |> unsafeOfSeq + + /// Returns the only element of the sequence. + /// The input sequence. + /// The only element of the sequence. + /// Thrown when the input does not have precisely one element. + let inline exactlyOne (source: NonEmptySeq<'T>) = Seq.exactlyOne source + + /// Returns a new sequence with the distinct elements of the input sequence which do not appear in the itemsToExclude sequence, using generic hash and equality comparisons to compare values. + /// The sequence of items to exclude from the input sequence. + /// The input sequence. + /// A sequence that contains the distinct elements of sequence that do not appear in itemsToExclude. + /// Thrown when itemsToExclude is null. + let inline except (itemsToExclude: #seq<'T>) (source: NonEmptySeq<'T>) = Seq.except itemsToExclude source |> unsafeOfSeq + + /// Tests if any element of the sequence satisfies the given predicate. + /// The function to test the input elements. + /// The input sequence. + /// True if any element satisfies the predicate. + let inline exists (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.exists predicate source + + /// Tests if any pair of corresponding elements of the sequences satisfies the given predicate. + /// The function to test the input elements. + /// The first input sequence. + /// The second input sequence. + /// True if any pair of elements satisfy the predicate. + /// Thrown when the input sequences are of different lengths. + let inline exists2 (predicate: 'T1 -> 'T2 -> bool) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) = + Seq.exists2 predicate source1 source2 + + /// Returns a new collection containing only the elements of the collection for which the given predicate returns "true." + /// The function to test the input elements. + /// The input sequence. + /// A sequence containing only the elements that satisfy the predicate. + let inline filter (predicate: 'T -> bool) (source: NonEmptySeq<'T>): NonEmptySeq<'T> = + source |> Seq.filter predicate |> unsafeOfSeq + + /// Returns a new collection containing only the elements of the collection for which the given predicate returns "true." + /// The function to test the input elements. + /// The input sequence. + /// A sequence containing only the elements that satisfy the predicate. + let inline tryFilter (predicate: 'T -> bool) (source: NonEmptySeq<'T>): 'T seq = + source |> Seq.filter predicate + + /// Returns the first element for which the given function returns True. + /// Raises if no such element exists. + /// The function to test the input elements. + /// The input sequence. + /// The first element that satisfies the predicate. + /// Thrown if the predicate evaluates to false for all the elements of the sequence. + let inline find (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.find predicate source + + /// Returns the last element for which the given function returns True. + /// Raises if no such element exists. + /// The function to test the input elements. + /// The input sequence. + /// The first element that satisfies the predicate. + /// Thrown if the predicate evaluates to false for all the elements of the sequence. + let inline findBack (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.findBack predicate source + + /// Returns the index of the first element in the sequence that satisfies the given predicate. + /// Raises if no such element exists. + /// The function to test the input elements. + /// The input sequence. + /// The first element that satisfies the predicate. + /// Thrown if the predicate evaluates to false for all the elements of the sequence. + let inline findIndex (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.findIndex predicate source + + /// Returns the index of the last element in the sequence that satisfies the given predicate. + /// Raises if no such element exists. + /// The function to test the input elements. + /// The input sequence. + /// The first element that satisfies the predicate. + /// Thrown if the predicate evaluates to false for all the elements of the sequence. + let inline findIndexBack (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.findIndexBack predicate source + + /// Applies a function to each element of the collection, threading an accumulator argument through the computation. + /// Take the second argument, and apply the function to it and the first element of the sequence. + /// Then feed this result into the function along with the second element and so on. + /// Return the final result. + /// If the input function is f and the elements are i0...iN then computes f (... (f s i0) i1 ...) iN. + /// The function to update the state given the input elements. + /// The initial state. + /// The input sequence. + /// The final state value. + let inline fold (folder: 'State -> 'T -> 'State) (state: 'State) (source: NonEmptySeq<'T>) = Seq.fold folder state source + + /// Applies a function to corresponding elements of two collections, threading an accumulator argument through the computation. + /// The collections must have identical sizes. + /// If the input function is f and the elements are i0...iN and j0...jN then computes f (... (f s i0 j0)...) iN jN. + /// The function to update the state given the input elements. + /// The initial state. + /// The first input sequence. + /// The second input sequence. + /// The final state value. + let inline fold2 (folder: 'State -> 'T1 -> 'T2 -> 'State) (state: 'State) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) = + Seq.fold2 folder state source1 source2 + + /// Applies a function to each element of the collection, starting from the end, threading an accumulator argument through the computation. + /// Take the second argument, and apply the function to it and the first element of the sequence. + /// Then feed this result into the function along with the second element and so on. + /// Return the final result. + /// If the input function is f and the elements are i0...iN then computes f i0 (...(f iN s)). + /// The function to update the state given the input elements. + /// The input sequence. + /// The initial state. + /// The final state value. + let inline foldBack (folder: 'T -> 'State -> 'State) (source: NonEmptySeq<'T>) (state: 'State) = + Seq.foldBack folder source state + + /// Applies a function to corresponding elements of two collections, threading an accumulator argument through the computation. + /// The collections must have identical sizes. + /// If the input function is f and the elements are i0...iN and j0...jN then computes f (... (f s i0 j0)...) iN jN. + /// The function to update the state given the input elements. + /// The first input sequence. + /// The second input sequence. + /// The initial state. + /// The final state value. + let inline foldBack2 (folder: 'T1 -> 'T2 -> 'State -> 'State) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) (state: 'State) = + Seq.foldBack2 folder source1 source2 state + + /// Tests if all elements of the collection satisfy the given predicate. + /// The function to test the input elements. + /// The input sequence. + /// True if all of the elements satisfy the predicate. + let inline forall (predicate: 'T -> bool) (source: NonEmptySeq<'T>) = Seq.forall predicate source + + /// Tests if all corresponding elements of the collection satisfy the given predicate pairwise. + /// The function to test the input elements. + /// The first input sequence. + /// The second input sequence. + /// True if all of the pairs of elements satisfy the predicate. + /// Thrown when the input sequences differ in length. + let inline forall2 (predicate: 'T1 -> 'T2 -> bool) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) = + Seq.forall2 predicate source1 source2 + + /// Applies a key-generating function to each element of a sequence and yields a sequence of unique keys. + /// Each unique key contains a sequence of all elements that match to this key. + /// A function that transforms an element of the sequence into a comparable key. + /// The input sequence. + /// The result sequence. + let inline groupBy (projection: 'T -> 'U) (source: NonEmptySeq<'T>) = + Seq.groupBy projection source + |> Seq.map (fun (k, v) -> (k, unsafeOfSeq v)) + |> unsafeOfSeq + /// Returns the first element of the sequence. /// /// The input sequence. @@ -151,6 +389,14 @@ module NonEmptySeq = /// The result sequence. let indexed (source: NonEmptySeq<_>) = Seq.indexed source |> unsafeOfSeq + /// Creates a sequence by applying a function to each index. + /// The number of elements to initialize. + /// A function that produces an element from an index. + /// The result sequence. + /// Thrown when count is less than or equal to zero. + let init (count: int) (initializer: int -> 'T) : NonEmptySeq<'T> = + Seq.init count initializer |> unsafeOfSeq + /// Generates a new sequence which, when iterated, will return successive /// elements by calling the given function. The results of calling the function /// will not be saved, that is the function will be reapplied as necessary to @@ -166,6 +412,68 @@ module NonEmptySeq = /// The result sequence. let initInfinite initializer = Seq.initInfinite initializer |> unsafeOfSeq + /// Inserts an element at the specified index. + /// The index at which to insert the element. + /// The value to insert. + /// The input sequence. + /// The result sequence. + let insertAt (index: int) (value: 'T) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.insertAt index value source |> unsafeOfSeq + + /// Inserts multiple elements at the specified index. + /// The index at which to insert the elements. + /// The values to insert. + /// The input sequence. + /// The result sequence. + let insertManyAt (index: int) (values: seq<'T>) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.insertManyAt index values source |> unsafeOfSeq + + /// Returns the element at the specified index. + /// The index of the element to retrieve. + /// The input sequence. + /// The element at the specified index. + /// Thrown when index is out of range. + let item (index: int) (source: NonEmptySeq<'T>) : 'T = + Seq.item index source + + /// Applies a function to each element of the sequence. + /// The function to apply to each element. + /// The input sequence. + let iter (action: 'T -> unit) (source: NonEmptySeq<'T>) : unit = + Seq.iter action source + + /// Applies a function to each element of the two sequences. + /// The function to apply to each pair of elements. + /// The first input sequence. + /// The second input sequence. + let iter2 (action: 'T1 -> 'T2 -> unit) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) : unit = + Seq.iter2 action source1 source2 + + /// Applies a function to each element of the sequence, passing the index of the element as the first argument to the function. + /// The function to apply to each element and its index. + /// The input sequence. + let iteri (action: int -> 'T -> unit) (source: NonEmptySeq<'T>) : unit = + Seq.iteri action source + + /// Applies a function to each element of the two sequences, passing the index of the elements as the first argument to the function. + /// The function to apply to each pair of elements and their index. + /// The first input sequence. + /// The second input sequence. + let iteri2 (action: int -> 'T1 -> 'T2 -> unit) (source1: NonEmptySeq<'T1>) (source2: NonEmptySeq<'T2>) : unit = + Seq.iteri2 action source1 source2 + + /// Returns the last element of the sequence. + /// The input sequence. + /// The last element of the sequence. + let last (source: NonEmptySeq<'T>) : 'T = + Seq.last source + + /// Returns the last element of the sequence. + /// The input sequence. + /// The last element of the sequence. + let length (source: NonEmptySeq<'T>) : int = + Seq.length source + /// Builds a new collection whose elements are the results of applying the given function /// to each of the elements of the collection. The given function will be applied /// as elements are demanded using the MoveNext method on enumerators retrieved from the @@ -322,6 +630,14 @@ module NonEmptySeq = /// This function consumes the whole input sequence before yielding the first element of the result sequence. let permute indexMap (source: NonEmptySeq<_>) = Seq.permute indexMap source |> unsafeOfSeq + /// Returns the first element for which the given function returns Some. If no such element exists, raises KeyNotFoundException. + /// A function to transform elements of the sequence into options. + /// The input sequence. + /// The first chosen element. + /// Thrown when no element is chosen. + let pick (chooser: 'T -> 'U option) (source: NonEmptySeq<'T>) : 'U = + Seq.pick chooser source + /// Builds a new sequence object that delegates to the given sequence object. This ensures /// the original sequence cannot be rediscovered and mutated by a type cast. For example, /// if given an array the returned sequence will return the elements of the array, but @@ -332,6 +648,47 @@ module NonEmptySeq = /// The result sequence. let readonly (source: NonEmptySeq<_>) = Seq.readonly source |> unsafeOfSeq + /// Applies a function to each element of the sequence, threading an accumulator argument + /// through the computation. Apply the function to the first two elements of the sequence. + /// Then feed this result into the function along with the third element and so on. + /// Return the final result. If the input function is f and the elements are i0...iN then computes + /// f (... (f i0 i1) i2 ...) iN. + /// The function to reduce two sequence elements to a single element. + /// The input sequence. + /// The final reduced value. + let reduce (reduction: 'T -> 'T -> 'T) source = Seq.reduce reduction source + + /// Applies a function to each element of the sequence, starting from the end, threading an accumulator argument + /// through the computation. If the input function is f and the elements are i0...iN then computes + /// f i0 (...(f iN-1 iN)). + /// A function that takes in the next-to-last element of the sequence and the + /// current accumulated result to produce the next accumulated result. + /// The input sequence. + /// The final result of the reductions. + let reduceBack (reduction: 'T -> 'T -> 'T) (source: NonEmptySeq<'T>) = Seq.reduceBack reduction source + + /// Removes the element at the specified index. + /// The index of the element to remove. + /// The input sequence. + /// The result sequence. + let removeAt (index: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.removeAt index source |> unsafeOfSeq + + /// Removes multiple elements starting at the specified index. + /// The index at which to start removing elements. + /// The number of elements to remove. + /// The input sequence. + /// The result sequence. + let removeManyAt (index: int) (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.removeManyAt index count source |> unsafeOfSeq + + /// Creates a sequence that contains one repeated value. + /// The number of elements. + /// The value to replicate. + /// The result sequence. + let replicate (count: int) (value: 'T) : NonEmptySeq<'T> = + Seq.replicate count value |> unsafeOfSeq + /// Returns a new sequence with the elements in reverse order. /// The input sequence. /// The reversed sequence. @@ -367,6 +724,20 @@ module NonEmptySeq = /// The result sequence of one item. let singleton value = Seq.singleton value |> unsafeOfSeq + /// Returns a sequence that skips the first N elements of the list. + /// The number of elements to skip. + /// The input sequence. + /// The result sequence. + let skip (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.skip count source |> unsafeOfSeq + + /// Returns a sequence that skips elements while the predicate is true. + /// A function to test each element of the sequence. + /// The input sequence. + /// The result sequence. + let skipWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.skipWhile predicate source |> unsafeOfSeq + /// Yields a sequence ordered by keys. /// /// This function returns a sequence that digests the whole initial sequence as soon as @@ -443,6 +814,26 @@ module NonEmptySeq = /// /// The result sequence. let sortByDescending projection (source: NonEmptySeq<_>) = Seq.sortByDescending projection source |> unsafeOfSeq + + /// Splits the list into the specified number of sequences. + /// The number of sequences to create. + /// The input list. + /// A sequence of sequences. + let splitInto (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq> = + Seq.splitInto count source |> Seq.map unsafeOfSeq |> unsafeOfSeq + + /// Computes the sum of the elements of the sequence. + /// The input sequence. + /// The sum of the elements. + let inline sum source = + Seq.sum source + + /// Computes the sum of the elements of the sequence, using the given projection. + /// A function to transform the sequence elements before summing. + /// The input sequence. + /// The sum of the transformed elements. + let inline sumBy projection source = + Seq.sumBy projection source /// Returns a sequence that skips 1 element of the underlying sequence and then yields the /// remaining elements of the sequence. @@ -452,6 +843,86 @@ module NonEmptySeq = /// The result sequence. let tail (source: NonEmptySeq<_>) = Seq.tail source + /// Returns a sequence that contains the first N elements of the sequence. + /// The number of elements to take. + /// The input sequence. + /// The result sequence. + let take (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.take count source |> unsafeOfSeq + + /// Returns a sequence that contains the elements of the sequence while the predicate is true. + /// A function to test each element of the sequence. + /// The input sequence. + /// The result sequence. + let takeWhile (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.takeWhile predicate source |> unsafeOfSeq + + /// Truncates the sequence to the specified length. + /// The maximum number of elements to include in the sequence. + /// The input sequence. + /// The truncated sequence. + let truncate (count: int) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.truncate count source |> unsafeOfSeq + + /// Returns the only element of the sequence, or None if the sequence does not contain exactly one element. + /// The input sequence. + /// The only element of the sequence, or None. + let tryExactlyOne (source: NonEmptySeq<'T>) : 'T option = + Seq.tryExactlyOne source + + /// Returns the first element for which the given function returns true, or None if no such element exists. + /// A function to test each element of the sequence. + /// The input sequence. + /// The first element for which the predicate returns true, or None. + let tryFind (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : 'T option = + Seq.tryFind predicate source + + /// Returns the last element for which the given function returns true, or None if no such element exists. + /// A function to test each element of the sequence. + /// The input sequence. + /// The last element for which the predicate returns true, or None. + let tryFindBack (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : 'T option = + Seq.tryFindBack predicate source + + /// Returns the index of the first element for which the given function returns true, or None if no such element exists. + /// A function to test each element of the sequence. + /// The input sequence. + /// The index of the first element for which the predicate returns true, or None. + let tryFindIndex (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : int option = + Seq.tryFindIndex predicate source + + /// Returns the index of the last element for which the given function returns true, or None if no such element exists. + /// A function to test each element of the sequence. + /// The input sequence. + /// The index of the last element for which the predicate returns true, or None. + let tryFindIndexBack (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : int option = + Seq.tryFindIndexBack predicate source + + /// Returns the element at the specified index, or None if the index is out of range. + /// The index of the element to retrieve. + /// The input sequence. + /// The element at the specified index, or None. + let tryItem (index: int) (source: NonEmptySeq<'T>) : 'T option = + Seq.tryItem index source + + /// Returns the last element of the sequence, or None if the sequence is empty. + /// The input sequence. + /// The last element of the sequence, or None. + let tryLast (source: NonEmptySeq<'T>) : 'T option = + Seq.tryLast source + + /// Returns the first element for which the given function returns Some, or None if no such element exists. + /// A function to transform elements of the sequence into options. + /// The input sequence. + /// The first chosen element, or None. + let tryPick (chooser: 'T -> 'U option) (source: NonEmptySeq<'T>) : 'U option = + Seq.tryPick chooser source + + /// Generates a list by repeatedly applying a function to a state. + /// A function that takes the current state and returns an option tuple of the next element and the next state. + /// The initial element. + /// The initial state. + /// The result list. let unfold (generator: 'T -> 'State -> ('T * 'State) option) (head: 'T) (state: 'State) = let rec go item state = seq { @@ -462,6 +933,34 @@ module NonEmptySeq = } go head state |> unsafeOfSeq + /// Splits a sequence of triples into three sequences. + /// The input sequence. + /// A tuple containing the three sequences. + let unzip3 (source: NonEmptySeq<'T1 * 'T2 * 'T3>) : NonEmptySeq<'T1> * NonEmptySeq<'T2> * NonEmptySeq<'T3> = + source |> Seq.toList |> List.unzip3 |> fun (a, b, c) -> (unsafeOfSeq a, unsafeOfSeq b, unsafeOfSeq c) + + /// Updates the element at the specified index. + /// The index of the element to update. + /// The new value. + /// The input sequence. + /// The result sequence. + let updateAt (index: int) (value: 'T) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.updateAt index value source |> unsafeOfSeq + + /// Returns a sequence that contains the elements of the sequence for which the given function returns true. + /// A function to test each element of the sequence. + /// The input sequence. + /// The result sequence. + let where (predicate: 'T -> bool) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = + Seq.where predicate source |> unsafeOfSeq + + /// Returns a sequence of sliding windows containing elements drawn from the sequence. + /// The number of elements in each window. + /// The input sequence. + /// The sequence of windows. + let windowed (windowSize: int) (source: NonEmptySeq<'T>) : NonEmptySeq> = + Seq.windowed windowSize source |> Seq.map unsafeOfSeq |> unsafeOfSeq + /// Combines the two sequences into a sequence of pairs. The two sequences need not have equal lengths: /// when one sequence is exhausted any remaining elements in the other /// sequence are ignored. @@ -518,23 +1017,6 @@ module NonEmptySeq = let replace (oldValue: NonEmptySeq<'T>) (newValue: NonEmptySeq<'T>) (source: NonEmptySeq<'T>) : NonEmptySeq<'T> = Seq.replace oldValue newValue source |> unsafeOfSeq - /// Returns a sequence that contains no duplicate entries according to the generic hash and equality comparisons - /// on the keys returned by the given key-generating function. - /// If an element occurs multiple times in the sequence then the later occurrences are discarded. - /// The input sequence. - /// The resulting sequence without duplicates. - let distinct (source: NonEmptySeq<'T>) = source |> Seq.distinct |> ofSeq - - /// Applies a function to each element of the sequence, threading an accumulator argument - /// through the computation. Apply the function to the first two elements of the sequence. - /// Then feed this result into the function along with the third element and so on. - /// Return the final result. If the input function is f and the elements are i0...iN then computes - /// f (... (f i0 i1) i2 ...) iN. - /// The function to reduce two sequence elements to a single element. - /// The input sequence. - /// The final reduced value. - let reduce (reduction: 'T -> 'T -> 'T) source = Seq.reduce reduction source - [] module NonEmptySeqBuilder =