i tried this following code what did i do wrong?
// Test IO
// Write a test file
let str : string[,] = Array2D.init 1 ASize (fun i j -> result.[i,j].ToString() )
System.IO.File.WriteAllLines(#"test.txt", str );
Will the first argument to Array2D.init in your code always be 1? If yes, then you can just create one dimensional array and it will work just fine:
let str = Array.init ASize (fun j -> result.[0,j].ToString() )
System.IO.File.WriteAllLines("test.txt", str );
If you really need to write a 2D array to a file, then you can convert 2D array into a one-dimensional array. The simplest way I can think of is this:
let separator = ""
let ar = Array.init (str.GetLength(0)) (fun i ->
seq { for j in 0 .. str.GetLength(1) - 1 -> str.[i, j] }
|> String.concat separator )
This generates a one-dimensional array (along the first coordinate) and then aggregates the elements along the second coordinate. It uses String.concat, so you can specify separator between the items on a single line.
because there are no overloads of File.WriteAllLines that accepts 2d array of strings. You should either convert it to 1d array or to seq<string>.
Related
I have recently started learning f# and I have a problem with a task like the one in the subject line. I managed to solve this task but not using a recursive function. I have tried to convert my function to a recursive function but it does not work because in the function I create arrays which elements I then change. Please advise me how to convert my function to a recursive function or how else to perform this task.
let list = [8;4;3;3;5;9;-7]
let comp (a,b) = if a>b then a elif b = a then a else b
let maks (b: _ list) =
let x = b.Length
if x % 2 = 0 then
let tab = Array.create ((x/2)) 0
for i = 0 to (x/2)-1 do
tab.[i] <- (comp(b.Item(2*i),b.Item(2*i+1)))
let newlist = tab |> Array.toList
newlist
else
let tab = Array.create (((x-1)/2)+1) 0
tab.[(((x-1)/2))] <- b.Item(x-1)
for i = 0 to ((x-1)/2)-1 do
tab.[i] <- (comp(b.Item(2*i),b.Item(2*i+1)))
let newlist = tab |> Array.toList
newlist
It is worth noting that, if you were doing this not for learning purposes, there is a nice way of doing this using the chunkBySize function:
list
|> List.chunkBySize 2
|> List.map (fun l -> comp(l.[0], l.[l.Length-1]))
This splits the list into chunks of size at most 2. For each chunk, you can then compare the first element with the last element and that is the result you wanted.
If this is a homework question, I don't want to give away the answer, so consider this pseudocode solution instead:
If the list contains at least two elements:
Answer a new list consisting of:
The greater of the first two elements, followed by
Recursively applying the function to the rest of the list
Else the list contains less than two elements:
Answer the list unchanged
Hint: F#'s pattern matching ability makes this easy to implement.
Thanks to your guidance I managed to create the following function:
let rec maks2 (b: _ list,newlist: _ list,i:int) =
let x = b.Length
if x >= 2 then
if x % 2 = 0 then
if i < ((x/2)-1)+1 then
let d = (porownaj(b.Item(2*i),b.Item(2*i+1)))
let list2 = d::newlist
maks2(b,list2,i+1)
else
newlist
else
if i < ((x/2)-1)+1 then
let d = (porownaj(b.Item(2*i),b.Item(2*i+1)))
let list2 = d::newlist
maks2(b,list2,i+1)
else
let list3 = b.Item(x-1)::newlist
list3
else
b
The function works correctly, it takes as arguments list, empty list and index.
The only problem is that the returned list is reversed, i.e. values that should be at the end are at the beginning. How to add items to the end of the list?
You can use pattern matching to match and check/extract lists in one step.A typical recursive function, would look like:
let rec adjGreater xs =
match xs with
| [] -> []
| [x] -> [x]
| x::y::rest -> (if x >= y then x else y) :: adjGreater rest
It checks wether the list is empty, has one element, or has two elements and the remaining list in rest.
Then it builds a new list by either using x or y as the first element, and then compute the result of the remaing rest recursivly.
This is not tail-recursive. A tail-call optimized version would be, that instead of using the result of the recursive call. You would create a new list, and pass the computed valuke so far, to the recursive function. Usually this way, you want to create a inner recursive loop function.
As you only can add values to the top of a list, you then need to reverse the result of the recursive function like this:
let adjGreater xs =
let rec loop xs result =
match xs with
| [] -> result
| [x] -> x :: result
| x::y::rest -> loop rest ((if x >= y then x else y) :: result)
List.rev (loop xs [])
I'm trying to read two integers which are going to be taken as input from the same line. My attempt so far:
let separator: char =
' '
Console.ReadLine().Split separator
|> Array.map Convert.ToInt32
But this returns a two-element array and I have to access the individual indices to access the integers. Ideally, what I would like is the following:
let (a, b) =
Console.ReadLine().Split separator
|> Array.map Convert.ToInt32
|> (some magic to convert the two element array to a tuple)
How can I do that?
I'm afraid there's no magic. You have to explicitly convert into a tuple
let a, b =
Console.ReadLine().Split separator
|> Array.map int
|> (fun arr -> arr.[0], arr.[1])
Edit: you can use reflection as #dbc suggested but that's slow and probably overkill for what you're doing.
I am new to programming and F# is my first language.
Here is my code:
let areAnagrams (firstString: string) (secondString: string) =
let countCharacters (someString: string) =
someString.ToLower().ToCharArray() |> Array.toSeq
|> Seq.countBy (fun eachChar -> eachChar)
|> Seq.sortBy (snd >> (~-))
countCharacters firstString = countCharacters secondString
let testString1 = "Laity"
let testString2 = "Italy"
printfn "It is %b that %s and %s are anagrams." (areAnagrams testString1 testString2) (testString1) (testString2)
This is the output:
It is false that Laity and Italy are anagrams.
What went wrong? What changes should I make?
Your implementation of countCharacters sorts the tuples just using the second element (the number of occurrences for each character), but if there are multiple characters that appear the same number of times, then the order is not defined.
If you run the countCharacters function on your two samples, you can see the problem:
> countCharacters "Laity";;
val it : seq<char * int> = seq [('l', 1); ('a', 1); ('i', 1); ('t', 1); ...]
> countCharacters "Italy";;
val it : seq<char * int> = seq [('i', 1); ('t', 1); ('a', 1); ('l', 1); ...]
One solution is to just use Seq.sort and sort the tuples using both the letter code and the number of occurrences.
The other problem is that you are comparing two seq<_> values and this does not use structural comparison, so you'll need to turn the result into a list or an array (something that is fully evaluated):
let countCharacters (someString: string) =
someString.ToLower().ToCharArray()
|> Seq.countBy (fun eachChar -> eachChar)
|> Seq.sort
|> List.ofSeq
Note that you do not actually need Seq.countBy - because if you just sort all the characters, it will work equally well (the repeated characters will just be one after another). So you could use just:
let countCharacters (someString: string) =
someString.ToLower() |> Seq.sort |> List.ofSeq
Sorting the characters of the two strings gives you an easy solution but this could be a good example of recursion.
You can immediately exclude strings of different length.
You can also filter out all the occurrences of a char per iteration, by replacing them with an empty string.
let rec areAnagram (x:string) (y:string) =
if x.Lenght <> t.Lenght
then false else
if x.Lenght = 0
then true else
let reply = x.[0].ToString ()
areAnagram
(x.Replace (reply,""))
(y.Replace (reply,""))
The above should be faster than sorting for many use cases.
Anyway we can go further and transform it into a fast Integer Sorting without recursion and string replacements
let inline charToInt c =
int c - int '0'
let singlePassAnagram (x:string) =
let hash : int array = Array.zeroCreate 100
x |> Seq.iter (fun c->
hash.[charToInt c] <- (hash.[charToInt c]+1)
)
let areAnagramsFast
(x:string) (y:string) =
if x.Length <> y.Length
then false else
(singlePassAnagram x) =
(singlePassAnagram y)
Here is a fiddle
I have a seq<'A>. I want to map this to a seq<(int, 'A)>, where the integer is an auto-generated sequence of values starting at 0. I know I can do this with a mutable counter and a loop, but is there a more elegant way to do this, perhaps using Seq.map?
Check out Seq.mapi: http://msdn.microsoft.com/en-us/library/ee340431.aspx
let a = [ 1; 2; 3 ]
let s = a |> Seq.mapi (fun i x -> i,x)
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