When to use a sequence in F# as opposed to a list?
Solution 1:
I think your summary for when to choose Seq
is pretty good. Here are some additional points:
- Use
Seq
by default when writing functions, because then they work with any .NET collection - Use
Seq
if you need advanced functions likeSeq.windowed
orSeq.pairwise
I think choosing Seq
by default is the best option, so when would I choose different type?
Use
List
when you need recursive processing using thehead::tail
patterns
(to implement some functionality that's not available in standard library)Use
List
when you need a simple immutable data structure that you can build step-by-step
(for example, if you need to process the list on one thread - to show some statistics - and concurrently continue building the list on another thread as you receive more values i.e. from a network service)Use
List
when you work with short lists - list is the best data structure to use if the value often represents an empty list, because it is very efficient in that scenarioUse
Array
when you need large collections of value types
(arrays store data in a flat memory block, so they are more memory efficient in this case)Use
Array
when you need random access or more performance (and cache locality)
Solution 2:
Also prefer seq
when:
You don't want to hold all elements in memory at the same time.
Performance is not important.
You need to do something before and after enumeration, e.g. connect to a database and close connection.
You are not concatenating (repeated
Seq.append
will stack overflow).
Prefer list
when:
There are few elements.
You'll be prepending and decapitating a lot.
Neither seq
nor list
are good for parallelism but that does not necessarily mean they are bad either. For example, you could use either to represent a small bunch of separate work items to be done in parallel.
Solution 3:
Just one small point: Seq
and Array
are better than List
for parallelism.
You have several options: PSeq from F# PowerPack, Array.Parallel module and Async.Parallel (asynchronous computation). List is awful for parallel execution due to its sequential nature (head::tail
composition).
Solution 4:
list is more functional, math-friendly. when each element is equal, 2 lists are equal.
sequence is not.
let list1 = [1..3]
let list2 = [1..3]
printfn "equal lists? %b" (list1=list2)
let seq1 = seq {1..3}
let seq2 = seq {1..3}
printfn "equal seqs? %b" (seq1=seq2)