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.
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 |