There is an approved proposal to make the functions defined in the List
, Array
, and Seq
modules in FSharp.Core.dll more regular and to add some new functions.
New functions added in this proposal: splitAt
, contains
, findBack
, tryFindBack
, findIndexBack
, tryFindIndexBack
, item
, tryItem
, indexed
, mapFold
, mapFoldBack
, tryLast
, tryHead
.
The F# 2.x and 3.x philosophy for these functions was somewhat irregular. The majority of functions (e.g. map
, filter
, groupBy
, averageBy
) were defined for Seq
, but some were not present on List
and Array
(e.g. groupBy
). This leads to awkward code where Seq
-producing functions are used even when List
is an input. Seq.groupBy
is a particular example.
Also, some functions were not defined on Seq
, even though they exist in List
or Array
.
The proposal below is to complete the matrix for List
, Array
and Seq
w.r.t. functional collection functions.
###Review and Completion
This work is only completed when all rows have a status of ":)". The library updates will only be done when all PRs are ready (or features are dropped).
- :) - reviewed and ready to be pulled
- :/ - reviewed but changes needed
- (empty) - no PR or not reviewed
If an item is marked "low-pri" it doesn't need to be completed in order for the library update to happen.
Function | Comment | List | Array | Seq | PR | Status |
---|---|---|---|---|---|---|
append |
o | o | o | --- | n/a | |
average |
o | o | o | --- | n/a | |
averageBy |
o | o | o | --- | n/a | |
contains |
new | ADD | ADD | ADD | PR | committed |
choose |
o | o | o | --- | n/a | |
chunkBySize |
ADD | ADD | ADD | PR | committed | |
collect |
o | o | o | --- | n/a | |
compareWith |
ADD | ADD | o | PR | committed | |
concat |
o | o | o | --- | n/a | |
countBy |
ADD | ADD | o | PR | committed | |
distinct |
ADD | ADD | o | PR | committed | |
distinctBy |
ADD | ADD | o | PR | committed | |
splitInto |
ADD | ADD | ADD | PR | committed | |
empty |
o | o | o | --- | n/a | |
exactlyOne |
ADD | ADD | o | PR | committed | |
except |
ADD | ADD | ADD | PR | committed | |
exists |
o | o | o | --- | n/a | |
exists2 |
o | o | o | --- | n/a | |
filter |
o | o | o | --- | n/a | |
find |
o | o | o | --- | n/a | |
findBack |
new | ADD | ADD | ADD | PR | committed |
findIndex |
o | o | o | --- | n/a | |
findIndexBack |
new | ADD | ADD | ADD | PR | committed |
fold |
o | o | o | --- | n/a | |
fold2 |
o | o | ADD | PR | committed | |
foldBack |
o | o | ADD | PR | committed | |
foldBack2 |
o | o | ADD | PR | committed | |
forall |
o | o | o | --- | n/a | |
forall2 |
o | o | o | --- | n/a | |
groupBy |
o | o | ADD | PR | committed | |
head |
o | ADD | o | PR | committed | |
indexed |
new, signature indexed: C<T> -> C<int*T> |
ADD | ADD | ADD | PR | committed |
init |
o | o | o | --- | n/a | |
isEmpty |
o | o | o | --- | n/a | |
item |
New, see note. Signature int -> C<'T> -> 'T |
ADD | ADD | ADD | PR | committed |
iter |
o | o | o | --- | n/a | |
iter2 |
o | o | o | --- | n/a | |
iteri |
o | o | o | --- | n/a | |
iteri2 |
o | o | ADD | PR | committed | |
last |
ADD | ADD | o | PR | committed | |
length |
o | o | o | --- | n/a | |
map |
o | o | o | --- | n/a | |
map2 |
o | o | o | --- | n/a | |
map3 |
o | ADD | ADD | PR | committed | |
mapi |
o | o | o | --- | n/a | |
mapi2 |
o | o | ADD | PR | committed | |
mapFold |
New, map + fold, with signature mapFold : ('State -> 'T -> 'U * 'State) -> 'State -> C<'T> -> C<'U> * 'State e.g. see here |
ADD | ADD | ADD | PR | committed |
mapFoldBack |
New, map + fold, with signature mapFoldBack : ('T -> 'State -> 'U * 'State) -> C<'T> -> 'State -> C<'U> * 'State |
ADD | ADD | ADD | PR | committed |
max |
o | o | o | --- | n/a | |
maxBy |
o | o | o | --- | n/a | |
min |
o | o | o | --- | n/a | |
minBy |
o | o | o | --- | n/a | |
nth |
see note | long-term deprecate, see note | o | long-term deprecate, see note | --- | n/a |
pairwise |
ADD | ADD | o | PR | committed | |
permute |
o | o | ADD | PR | committed | |
pick |
o | o | o | --- | n/a | |
reduce |
o | o | o | --- | n/a | |
reduceBack |
o | o | ADD | PR | committed | |
replicate |
o | ADD | ADD | PR | committed | |
rev |
o | o | ADD | PR | committed | |
scan |
o | o | o | --- | n/a | |
scanBack |
o | o | ADD | PR | committed | |
singleton |
ADD | ADD | o | PR | committed | |
skip |
ADD | ADD | o | PR | committed | |
skipWhile |
ADD | ADD | o | PR | committed | |
sort |
o | o | o | --- | n/a | |
sortBy |
o | o | o | --- | n/a | |
sortWith |
o | o | ADD | PR | committed | |
sortDescending |
ADD | ADD | ADD | PR | committed | |
sortByDescending |
ADD | ADD | ADD | PR | committed | |
sum |
o | o | o | --- | n/a | |
sumBy |
o | o | o | --- | n/a | |
tail |
o | ADD | ADD | PR | committed | |
take |
ADD | ADD | o | PR | committed | |
takeWhile |
ADD | ADD | o | PR | committed | |
truncate |
ADD | ADD | o | PR | committed | |
tryFind |
o | o | o | --- | n/a | |
tryFindBack |
new | ADD | ADD | ADD | PR | committed |
tryFindIndex |
o | o | o | --- | n/a | |
tryFindIndexBack |
new | ADD | ADD | ADD | PR | committed |
tryHead |
new | ADD | ADD | ADD | PR | committed |
tryItem |
new | ADD | ADD | ADD | PR | committed |
tryLast |
new | ADD | ADD | ADD | PR | committed |
tryPick |
o | o | o | --- | n/a | |
unfold |
ADD | ADD | o | PR | committed | |
where |
syn. filter | ADD | ADD | o | PR | committed |
windowed |
ADD | ADD | o | PR | committed | |
zip |
o | o | o | --- | n/a | |
zip3 |
o | o | o | --- | n/a |
Note: In F# 3.0 Seq.where
was defined as a synonym for Seq.filter
, mainly due to the use of "where" in query expressions. Given it already exists as a synonym (= decision made) it seems sensible to just complete the matrix and define List.where
and Array.where
as well.
Note: In F# 3.x, nth
is defined with inconsistent signatures for Array
and List
. The proposal above replaces nth
by item
and would eventually deprecate nth
(with a message to say 'please use Seq.item'. It also adds a corresponding tryItem
. Both item
and tryItem
would take the integer index as the first parameter.
These operators are not defined for Seq.*
for performance reasons because using them would require iterating the input sequence twice.
Note it is arguable that if these are not defined, then Seq.tail
, Seq.skip
and Seq.skipWhile
should also not be defined, since they implicitly skip inputs and can be a performance trap, especially when used recursively.
Function | Comment | List | Array | Seq | PR | Status |
---|---|---|---|---|---|---|
partition |
o | o | n/a | --- | n/a | |
splitAt |
new, taking index | ADD | ADD | n/a | PR | committed |
unzip |
o | o | n/a | --- | n/a | |
unzip3 |
o | o | n/a | --- | n/a |
Function | Comment | List | Array | Seq | PR | Status |
---|---|---|---|---|---|---|
blit |
n/a | o | n/a | --- | n/a | |
copy |
n/a | o | n/a | --- | n/a | |
create |
n/a | o | n/a | --- | n/a | |
fill |
n/a | o | n/a | --- | n/a | |
get |
n/a | o | n/a | --- | n/a | |
set |
n/a | o | n/a | --- | n/a | |
sortInPlace |
n/a | o | n/a | --- | n/a | |
sortInPlaceBy |
n/a | o | n/a | --- | n/a | |
sortInPlaceWith |
n/a | o | n/a | --- | n/a | |
sub |
n/a | o | n/a | --- | n/a | |
zeroCreate |
n/a | o | n/a | --- | n/a |
Function | Comment | List | Array | Seq | PR | Status |
---|---|---|---|---|---|---|
ofList |
n/a | o | o | --- | n/a | |
ofArray |
o | n/a | o | --- | n/a | |
ofSeq |
o | o | n/a | --- | n/a | |
toList |
n/a | o | o | --- | n/a | |
toArray |
o | n/a | o | --- | n/a | |
toSeq |
o | o | n/a | --- | n/a |
Function | Comment | List | Array | Seq | PR | Status |
---|---|---|---|---|---|---|
cache |
n/a | n/a | o | --- | n/a | |
cast |
n/a | n/a | o | --- | n/a | |
delay |
n/a | n/a | o | --- | n/a | |
initInfinite |
n/a | n/a | o | --- | n/a | |
readonly |
n/a | n/a | o | --- | n/a |