How can I overload .[] for F# array to slice an array based on an arbitrary index array?
For example:
let x = [|1..10|];
let indx = [|4;1|];
although
[| for i in indx ->x.[i]|]
would work, it would be nicer to be able using x.[indx] directly.
You can always write an F# extension method to get close on the syntax
let a = [| 1..10 |]
let idx = [|4;1|]
type 'T ``[]`` with //'
member this.Slice(indices:int array) =
[| for i in indices -> this.[i] |]
printfn "%A" (a.Slice idx)
but since arrays already have an indexer it doesn't appear there's a way to overload/change it.
Related
is there a way to flatten tuples of arbitrary size in F# without explicitly mapping them?
(fun ((((a0,a1),a2),b),c) -> (a0,a1,a2,b,c))
As a note I'm getting these kind of tuples from FParsec but the capability would be convenient if it was available generally.
thanks,
You can't do it easily, but with a bit of reflection it is possible:
let isTuple tuple =
Microsoft.FSharp.Reflection.FSharpType.IsTuple(tuple.GetType())
let tupleValues (tuple : obj) =
Microsoft.FSharp.Reflection.FSharpValue.GetTupleFields tuple |> Array.toList
let rec flatten tupleFields =
tupleFields |> List.collect(fun value ->
match isTuple value with
| true -> flatten (tupleValues value)
| false -> [value]
)
let tupleToList (tuple : obj) =
if isTuple tuple
then Some (tupleValues tuple |> flatten)
else None
So, for example:
let s = tupleToList ((100,101,102,103),1,2,3,(4,5))
Will give you:
[100; 101; 102; 103; 1; 2; 3; 4; 5]
NOTE: This answer is based on code found here.
I have the following array CF which contains arrays. How can I set up another array of same length as CF which finds the nth element of arrays within CF.
let CF= [|for i in 0..(Connection.Length-1)->
res RProject.[i] rc.[i] D.[i] in.[i]|]
If I understand the question correctly, you want the nth element of each array, mapped to a new array. You can do this with Array.map.
Here's an example. First, an array of arrays:
let a1 = [| [|1; 2; 3|]; [| 4; 5; 6 |] |]
Let's say you want the second element in each of these arrays, mapped into a new array. This can be done like this:
let a2 = a1 |> Array.map (fun a -> [| a.[1] |])
In this example, a2 will now have the value [|[|2|]; [|5|]|].
Notice that an exception will be thrown if you attempt to access an array index that is outside the bounds of any of the arrays.
I am new to programming, and this is my first time working with a typed, functional, and .NET language, so pardon me if my question is silly/trivial.
I have a list of tuples, and I would like to store the first item (which is a string) of each tuple as a value in the hashtable, and the second item (which is a byte array) of each tuple as a key. How may I go about doing so?
Here is my code:
let readAllBytes (tupleOfFileLengthsAndFiles) =
let hashtable = new Hashtable()
tupleOfFileLengthsAndFiles
|> snd
|> List.map (fun eachFile -> (eachFile, File.ReadAllBytes eachFile))
|> hashtable.Add(snd eachTuple, fst eachTuple)
However, the last line is underscored in red. How can I improve it? Thanks in advance for your help.
The easies way is to use dict
It will convert a sequence of tuples in a Dictionary which is a string type Hashtable.
> dict [(1,"one"); (2,"two"); ] ;;
val it : System.Collections.Generic.IDictionary<int,string> =
seq [[1, one] {Key = 1;
Value = "one";}; [2, two] {Key = 2;
Value = "two";}]
If you are really interested in a Hashtable you can use this simple function:
let convert x =
let d = Hashtable()
x |> Seq.iter d.Add
d
So, I'm not sure what do you want to do with this, it seems you're also interested in reading the file in the middle of the conversion. May be something like this:
let readAllBytes (tupleOfFileLengthsAndFiles:seq<'a*'b>) =
tupleOfFileLengthsAndFiles
|> Seq.map (fun (x, y) -> x, File.ReadAllBytes y)
|> convert
I've trying to learn F#. I'm a complete beginner, so this might be a walkover for you guys :)
I have the following function:
let removeEven l =
let n = List.length l;
let list_ = [];
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
let list_ = list_ # [x];
list_;
It takes a list, and return a new list containing all the numbers, which is placed at an odd index in the original list, so removeEven [x1;x2;x3] = [x1;x3]
However, I get my already favourite error-message: Incomplete construct at or before this point in expression...
If I add a print to the end of the line, instead of list_:
...
print_any list_;
the problem is fixed. But I do not want to print the list, I want to return it!
What causes this? Why can't I return my list?
To answer your question first, the compiler complains because there is a problem inside the for loop. In F#, let serves to declare values (that are immutable and cannot be changed later in the program). It isn't a statement as in C# - let can be only used as part of another expression. For example:
let n = 10
n + n
Actually means that you want the n symbol to refer to the value 10 in the expression n + n. The problem with your code is that you're using let without any expression (probably because you want to use mutable variables):
for x in seq_ do
let list_ = list_ # [x] // This isn't assignment!
list_
The problematic line is an incomplete expression - using let in this way isn't allowed, because it doesn't contain any expression (the list_ value will not be accessed from any code). You can use mutable variable to correct your code:
let mutable list_ = [] // declared as 'mutable'
let seq_ = seq { for x in 1..n do if x % 2 <> 0 then yield List.nth l (x-1)}
for x in seq_ do
list_ <- list_ # [x] // assignment using '<-'
Now, this should work, but it isn't really functional, because you're using imperative mutation. Moreover, appending elements using # is really inefficient thing to do in functional languages. So, if you want to make your code functional, you'll probably need to use different approach. Both of the other answers show a great approach, although I prefer the example by Joel, because indexing into a list (in the solution by Chaos) also isn't very functional (there is no pointer arithmetic, so it will be also slower).
Probably the most classical functional solution would be to use the List.fold function, which aggregates all elements of the list into a single result, walking from the left to the right:
[1;2;3;4;5]
|> List.fold (fun (flag, res) el ->
if flag then (not flag, el::res) else (not flag, res)) (true, [])
|> snd |> List.rev
Here, the state used during the aggregation is a Boolean flag specifying whether to include the next element (during each step, we flip the flag by returning not flag). The second element is the list aggregated so far (we add element by el::res only when the flag is set. After fold returns, we use snd to get the second element of the tuple (the aggregated list) and reverse it using List.rev, because it was collected in the reversed order (this is more efficient than appending to the end using res#[el]).
Edit: If I understand your requirements correctly, here's a version of your function done functional rather than imperative style, that removes elements with odd indexes.
let removeEven list =
list
|> Seq.mapi (fun i x -> (i, x))
|> Seq.filter (fun (i, x) -> i % 2 = 0)
|> Seq.map snd
|> List.ofSeq
> removeEven ['a'; 'b'; 'c'; 'd'];;
val it : char list = ['a'; 'c']
I think this is what you are looking for.
let removeEven list =
let maxIndex = (List.length list) - 1;
seq { for i in 0..2..maxIndex -> list.[i] }
|> Seq.toList
Tests
val removeEven : 'a list -> 'a list
> removeEven [1;2;3;4;5;6];;
val it : int list = [1; 3; 5]
> removeEven [1;2;3;4;5];;
val it : int list = [1; 3; 5]
> removeEven [1;2;3;4];;
val it : int list = [1; 3]
> removeEven [1;2;3];;
val it : int list = [1; 3]
> removeEven [1;2];;
val it : int list = [1]
> removeEven [1];;
val it : int list = [1]
You can try a pattern-matching approach. I haven't used F# in a while and I can't test things right now, but it would be something like this:
let rec curse sofar ls =
match ls with
| even :: odd :: tl -> curse (even :: sofar) tl
| even :: [] -> curse (even :: sofar) []
| [] -> List.rev sofar
curse [] [ 1; 2; 3; 4; 5 ]
This recursively picks off the even elements. I think. I would probably use Joel Mueller's approach though. I don't remember if there is an index-based filter function, but that would probably be the ideal to use, or to make if it doesn't exist in the libraries.
But in general lists aren't really meant as index-type things. That's what arrays are for. If you consider what kind of algorithm would require a list having its even elements removed, maybe it's possible that in the steps prior to this requirement, the elements can be paired up in tuples, like this:
[ (1,2); (3,4) ]
That would make it trivial to get the even-"indexed" elements out:
thelist |> List.map fst // take first element from each tuple
There's a variety of options if the input list isn't guaranteed to have an even number of elements.
Yet another alternative, which (by my reckoning) is slightly slower than Joel's, but it's shorter :)
let removeEven list =
list
|> Seq.mapi (fun i x -> (i, x))
|> Seq.choose (fun (i,x) -> if i % 2 = 0 then Some(x) else None)
|> List.ofSeq
I am trying to write an efficient algorithm that will effectively let me merge data sets (like a sql join). I think I need to use Array.tryFindIndex, but the syntax has me lost.
Based on the data below, I am calling arrX my "host" array, and want to return an int array that has its length, and tells me the positions of each of its elements in arrY (returning -1 if its not in there). (Once I know these indices I can then use them on arrays of data that of length arrY.length)
let arrX= [|"A";"B";"C";"D";"E";"F"|]
let arrY = [|"E";"A";"C"|];
let desiredIndices = [|1; -1; 2; -1; 0; -1|]
It looks like I need to use an option type somehow, and I think a mapi2 in there as well.
Does anyone know how to get this done? (I think it could be a very useful code snippet for people who are merging data sets from different sources)
Thanks!
//This code does not compile, can't figure out what to do here
let d = Array.tryFindIndex (fun x y -> x = y) arrX
The tryFindIndex function searches for a single element in the array specified as the second argument. The lambda function gets only a single parameter and it should return true if the parameter is the element you are looking for. The type signature of the tryFindIndex function shows this:
('a -> bool) -> 'a [] -> int option
(In your example, you're giving it a function that takes two parameters of type 'a -> 'a -> bool, which is incompatible with the expected type). The tryFindIndex function returns an option type, which means that it gives you None if no element matches the predicate, otherwise it gives you Some(idx) containing the index of the found element.
To get the desired array of indices, you need to run tryFindIndex for every element of the input array (arrX). This can be done using the Array.map function. If you want to get -1 if the element wasn't found, you can use pattern matching to convert None to -1 and Some(idx) to idx:
let desired =
arrX |> Array.map (fun x ->
let res = Array.tryFindIndex (fun y -> x = y) arrY
match res with
| None -> -1
| Some idx -> idx)
The same thing can be written using sequence expression (instead of map), which may be more readable:
let desired =
[| for x in arrX do
let res = Array.tryFindIndex (fun y -> x = y) arrY
match res with
| None -> yield -1
| Some idx -> yield idx |]
Anyway, if you need to implement a join-like operation, you can do it more simply using sequence expressions. In the following example, I also added some values (in addition to the string keys), so that you can better see how it works:
let arrX= [|"A",1; "B",2; "C",3; "D",4; "E",5; "F",6|]
let arrY = [|"E",10; "A",20; "C",30|]
[| for x, i in arrX do
for y, j in arrY do
if x = y then
yield x, i, j |]
// Result: [|("A", 1, 20); ("C", 3, 30); ("E", 5, 10)|]
The sequence expression simply loops over all arrX elements and for each of them, it loops over all arrY element. Then it tests whether the keys are the same and if they are, it produces a single element. This isn't particularly efficient, but in most of the cases, it should work fine.
Write a custom function that returns -1 if nothing is found, or returns the index if it's found. Next, use Array.map to map a new array using this function:
let arrX= [|"A";"B";"C";"D";"E";"F"|]
let arrY = [|"E";"A";"C"|];
let indexOrNegativeOne x =
match Array.tryFindIndex (fun y -> y = x) arrY with
| Some(y) -> y
| None -> -1
let desired = arrX |> Array.map indexOrNegativeOne
printfn "%A" desired