6

Given a list, I would like to produce a second list of elements selected from the first one.

For example:

let l1 = [1..4]
let n = [0; 2]
l1.[n]

should return 1 and 3, the first and third element of l1. Unfortunately, it returns an error:

error FS0001: This expression was expected to have type
int but here has type int list

Now, I wonder, does exist a way to pass an argument n representing a list or, even better, an expression?

Worice
  • 3,847
  • 3
  • 28
  • 49
  • 3
    `n |> List.map (List.nth l1)`? – ildjarn Nov 13 '16 at 17:58
  • 2
    Is there a broader reason as to why you want to do this? Accessing a list element by index is O(n) so it isn't a terribly good thing to do repeatedly. – TheInnerLight Nov 13 '16 at 18:38
  • 1
    I used it quite often in R programming. I found it quite practical. I know that those languages as quite different, hence I am working on my mindset. A possible problem to solve could be access one element yes and one element no of a list. – Worice Nov 13 '16 at 18:46
  • 4
    If you need random access, use arrays rather than lists. That's what they are for. – scrwtp Nov 13 '16 at 19:47
  • Thanks @scrwtp, I will use them for sure when I will use random access! – Worice Nov 13 '16 at 20:00

3 Answers3

7

F# doesn't offer syntactical support for that sort of indexing. You can ask for a continuous slice of an array like below, but it doesn't cover your exact scenario.

let a = [|1 .. 4|]
let b = a.[0..2]
// returns [|1; 2; 3|]

You can easily write a function for that though:

let slice<'a> (indices: int list) (arr: 'a array) = 
    [| for idx in indices do yield arr.[idx] |]

slice [0; 2] a 
// returns [| 1; 3 |]

I'm leaving proper handling of out-of-bounds access as an exercise ;)

scrwtp
  • 13,437
  • 2
  • 26
  • 30
  • Really interesting! Why do think that this approach is not supported in F#? Is it that inefficient? Thanks for the example! – Worice Nov 13 '16 at 20:05
  • 1
    It's just a rare feature to see in a general-purpose programming language. – scrwtp Nov 13 '16 at 20:36
  • 2
    @Worice This type of fancy indexing is common in languages that are domain specific to matrix manipulation. As scrwtp points it out F# is a general-purpose languages with many other data structures that serve a similar need. I recall that you can pass a list of indices to Deedle in a similar way. However this could still be a nice feature for matrix manipulation in [Mathnet.Numerics](http://numerics.mathdotnet.com/Matrix.html), currently the work around is in the above Answer or [this one](http://stackoverflow.com/questions/40466407/how-to-shuffle-a-densematrix-in-f/40477039#40477039). – s952163 Nov 13 '16 at 23:49
  • Thanks @s952163 for the reference. – Worice Nov 14 '16 at 13:44
3

With indexed properties, you should be able to define this for your types: just define a member Item with get(indexes) which accepts a list/array. But standard lists and arrays already have Item defined, and you can't have two at once...

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
3

I solved it this way:

List.map (fun index -> l1.[index]) n

It's inefficient for large lists, but works for me.

Christian Davén
  • 16,713
  • 12
  • 64
  • 77