Common functions

Functions available in multiple modules, each version customized for its target type

Operations: access, construct, find, select, aggregate...

โ˜๏ธ Convention used here:

  1. Functions are given by their name

    • To use them, we need to qualify them by the module.

  2. The last parameter is omitted for brevity

    • It's always the collection.

Example: head vs List.head x

Access to an element

โ†“ Access \ Return element โ†’
Directly or ๐Ÿ’ฃ
Optionally

By index

x[index]

By index

item index

tryItem index

First element

head

tryHead

Last element

last

tryLast

๐Ÿ’ฃ ArgumentException or IndexOutOfRangeException

[1; 2] |> List.tryHead    // Some 1
[1; 2] |> List.tryItem 2  // None

Cost โš ๏ธ

โ†“ Function \ Module โ†’
Array
List
Seq

head

O(1)

O(1)

O(1)

item

O(1)

O(n) โ—

O(n) โ—

last

O(1)

O(n) โ—

O(n) โ—

length

O(1)

O(n) โ—

O(n) โ—

Combine collections

Function
Parameters
Final size

append / @

2 collections of sizes N1 et N2

N1 + N2

concat

K collections of sizes N1..Nk

N1 + N2 + ... + Nk

zip

2 collections of same size N โ—

N pairs

allPairs

2 collections of sizes N1 et N2

N1 * N2 pairs

Find an element

Using a predicate f : 'T -> bool:

โ†“ Which element \ Returns โ†’
Direct or ๐Ÿ’ฃ
Optional

First found

find

tryFind

Last found

findBack

tryFindBack

Index of first found

findIndex

tryFindIndex

Index of last found

findIndexBack

tryFindIndexBack

Search elements

Search
How many items
Function

By value

At least 1

contains value

By predicate f

At least 1

exists f

"

All

forall f

Select elements

โ†“ Which elements \ Search โ†’
By size
By predicate

All those found

filter f

First ignored

skip n

skipWhile f

First found

take n

takeWhile f

truncate n

โ˜ Notes:

  • skip, take vs truncate when n > collection's size

    • skip, take: ๐Ÿ’ฃ exception

    • truncate: empty collections w/o exception

  • Alternative for Array: Range arr[2..5]

Map elements

Functions taking as input:

  • A mapping function f (a.k.a. mapper)

  • A collection of type ~~~~ 'T with ~~~~ meaning Array, List, or Seq

Function
Mapping f
Returns
How many elements?

map

ย ย ย ย ย ย ย 'T -> 'Uย ย ย ย ย ย 

'U ~~~~

As many in than out

mapi

int -> 'T -> 'Uย ย ย ย ย ย 

'U ~~~~

As many in than out

collect

ย ย ย ย ย ย ย 'T -> 'U ~~~~ย 

'U ~~~~

flatMap

choose

ย ย ย ย ย ย ย 'T -> 'U option

'U ~~~~

Less

pick

ย ย ย ย ย ย ย 'T -> 'U option

'Uย ย ย ย ย 

1 (the first matching) or ๐Ÿ’ฃ

tryPick

ย ย ย ย ย ย ย 'T -> 'U option

'U option

1 (the first matching)

map vs mapi

mapi โ‰ก map with index

The difference is on the f mapping parameter:

  • map: 'T -> 'U

  • mapi: int -> 'T -> 'U โ†’ the additional int parameter is the item index

Alternative to mapi

Apart from map and iter, no xxx function has a xxxi variant.

๐Ÿ’ก Use indexed to obtain elements with their index

map vs iter

iter looks like map with

  • no mapping: 'T -> unit vs 'T -> 'U

  • no output: unit vs 'U list

But iter is used for a different use case: โ†’ to trigger an action, a side-effect, for each item

Example: print the item to the console

choose, pick, tryPick

Signatures:

โ€ข choose : mapper: ('T -> 'U option) -> items: 'T ~~~~ -> 'U ~~~~ โ€ข pick : mapper: ('T -> 'U option) -> items: 'T ~~~~ -> 'U โ€ข tryPick : mapper: ('T -> 'U option) -> items: 'T ~~~~ -> 'U option

Notes:

  • The mapper may return None for some items not mappable (or just ignored)

  • ~~~~ stands for the collection type: Array, List, or Seq

Different use cases:

  • choose to get all the mappable items mapped

  • pick or tryPick to get the first one

When no items are mappable:

  • choose returns an empty collection

  • tryPick returns None

  • pick raises a KeyNotFoundException ๐Ÿ’ฃ

Examples:

Analogies:

choose f โ‰ƒ โ€ข collect (f >> Option.to{Collection}) โ€ข (filter (f >> Option.isSome)) >> (map (f >> Option.value))

(try)pick f โ‰ƒ โ€ข (try)find(f >> Option.isSome)) >> f โ€ข choose f >> (try)head

Aggregate

Specialized aggregate functions

Direct
By projection
Mapping
Constraint

ร—

countBy

ร—

max

maxBy

comparison

min

minBy

comparison

sum

sumBy

Monoid๐Ÿ“

average

averageBy

Monoid๐Ÿ“

Warning

CountBy

Uses a projection f: 'T -> 'U to compute a "key" for each item Returns all the keys with the number of items having this key

๐Ÿ’ก Useful to determine duplicates:

Max(By), Min(By)

โ˜๏ธ Notes:

  • Unions are IComparable by default โ†’ N follows the comparison constraint.

  • maxBy and minBy perform no mapping: โ†’ See the returned value in the example: Two (N), โ‰  "Two" (string)

Sum(By), Average(By)

โ˜๏ธ Notes:

  • The error FS0001 at line 1 reveals the Monoid constraint (see below) that must be satisfied by:

    • The item type 'T for sum and average,

    • The projection return type 'U for sumBy and averageBy.

  • sumBy and averageBy perform a mapping โ†’ See the returned type in the example: int โ‰  item type: int * string

  • sum โ‰ก sumBy id average โ‰ก averageBy id

Monoid constraint

To satisfy the monoid constraint, a type must have:

  • A Zero static read-only property

  • An overload of the + operator

Example of a custom type with these members:

Versatile aggregate functions

โ€ข fold (f: 'U -> 'T -> 'U) (seed: 'U) items โ€ข foldBack (f: 'T -> 'U -> 'U) items (seed: 'U) โ€ข reduce (f: 'T -> 'T -> 'T) items โ€ข reduceBack (f: 'T -> 'T -> 'T) items

f takes 2 parameters: an "accumulator" acc and the current element x โ†’ For foldBack, the parameters are in a reversed order: x acc

xxxBack vs xxx:

  • Iterates from last to first element

  • Parameters seed and items reversed (for foldBack)

reduce(Back) vs fold(Back):

  • reduce(Back) uses the first item as the seed and performs no mapping (see 'T -> 'T vs 'T -> 'U)

  • reduce(Back) fails if the collection is empty ๐Ÿ’ฃ

Examples:

Fold(Back) versatility

We could write almost all functions with fold or foldBack (performance aside)

Change the order of elements

Operation
Direct
Mapping

Inversion

rev list

ร—

Sort asc

sort list

sortBy f list

Sort desc

sortDescending list

sortDescendingBy f list

Sort custom

sortWith comparer list

ร—

Separate

๐Ÿ’ก Elements are divided into groups

Operation
Result (; omitted)
Remark

[1..10]

[ 1 2 3 4 5 6 7 8 9 10 ]

length = 10

chunkBySize 3

[[1 2 3] [4 5 6] [7 8 9] [10]]

forall: length <= 3

splitInto 3

[[1 2 3 4] [5 6 7] [8 9 10]]

length <= 3

splitAt 3

([1 2 3],[4 5 6 7 8 9 10])

Tuple โ—

โ˜๏ธ Notice how splitInto n distributes the items equally, from left to right:

Group items

By size

๐Ÿ’ก Items can be duplicated into different groups

Operation
Result (' and ; omitted)
Remark

[1..5]

[ 1 2 3 4 5 ]

pairwise

[(1,2) (2,3) (3,4) (4,5)]

Tuple โ—

windowed 2

[[1 2] [2 3] [3 4] [4 5]]

Array of arrays of 2 items

windowed 3

[[1 2 3] [2 3 4] [3 4 5]]

Array of arrays of 3 items

By criteria

Operation
Criteria
Result

partition

predicate: 'T -> bool

('T list * 'T list)

โ†’ 1 pair ([OKs], [KOs])

groupBy

projection: 'T -> 'K

('K * 'T list) list

โ†’ N tuples [(key, [related items])]

Change collection type

Your choice: Dest.ofSource or Source.toDest

From \ to

Array

List

Seq

Array

ร—

List.ofArray

Seq.ofArray

ร—

Array.toList

Array.toSeq

List

Array.ofList

ร—

Seq.ofList

List.toArray

ร—

List.toSeq

Seq

Array.ofSeq

List.ofSeq

ร—

Seq.toArray

Seq.toList

ร—

Functions vs comprehension

The functions of List/Array/Seq can often be replaced by a comprehension, more versatile:

Additional resources

Documentation FSharp.Core ๐Ÿ‘

Last updated

Was this helpful?