Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I append to a list in F# rather than prepend?

Tags:

f#

Prepending to a list in F# is somewhat annoying because once you're done you have to reverse it. Is there a way to build a list straight from start?

like image 743
Trident D'Gao Avatar asked Sep 17 '13 14:09

Trident D'Gao


People also ask

How to Add to a list in f#?

You can attach elements to a list by using the :: (cons) operator. If list1 is [2; 3; 4] , the following code creates list2 as [100; 2; 3; 4] . You can concatenate lists that have compatible types by using the @ operator, as in the following code.

What is append() in Python?

Append in Python is a pre-defined method used to add a single item to certain collection types. Without the append method, developers would have to alter the entire collection's code for adding a single value or item. Its primary use case is seen for a list collection type.

What do you mean by append() in list?

The append() method appends an element to the end of the list.

Are lists mutable in F#?

The List<'T> class represents a strongly typed list of objects that can be accessed by index. It is a mutable counterpart of the List class. It is similar to arrays, as it can be accessed by an index, however, unlike arrays, lists can be resized.


2 Answers

There is nothing wrong with prepending and reversing the list. You can use append (@) on a single-element list, but it is a code smell. A tolerable (tail-recursive) approach is:

let appendSingle xs x =
    [ yield! xs
      yield x ]

All the above solutions have O(n) execution time. For your use case, you could keep a private ResizeArray to avoid the use of reverse. It is fine since mutability is hidden. Compare this function

let filter f l = 
  let rec loop acc l =
    match l with 
    | [] -> List.rev acc                        
    | x::xs when f x -> loop (x::acc) xs  
    | x::xs -> loop acc xs
  loop [] l

with its more efficient counterpart

let filter f l = 
  let rec loop (acc : ResizeArray<_>) l =
    match l with 
    | [] -> Seq.toList acc                        
    | x::xs when f x -> 
        acc.Add(x)  
        loop acc xs  
    | x::xs -> loop acc xs
  loop (ResizeArray()) l
like image 44
pad Avatar answered Sep 26 '22 03:09

pad


If you need to append elements to the end, you can use the type known as DList. There is an implementation available in FSharpX.

However, there is some runtime overhead associated with this (e.g. see the comments here) and so I think that building list by prepending and then reversing is generally going to be more efficient. It is also quite standard thing to do in functional programming - it may look a bit confusing at first, but it is a very common "design pattern" when implementing recursive functions that walk over lists, so I would not try to avoid it.

like image 176
Tomas Petricek Avatar answered Sep 26 '22 03:09

Tomas Petricek