F# Seq diff - f#

given two sequences, how to get all the elements belonging to both the sequences or all the elements unique to one of them?
Example:
let a = [1..10]
let b = [3; 5; 7]
How do I compute 3 5 and 7 (all the elements common to both the list) and 1, 2, 4, 6, 8, 9, 10 (all the elements not in common)
Thanks

What you want to do is no more than the simple set operations of intersection and difference (or relative complement).
F# has the Set module to help us out here. This should do the job:
let a = [1 .. 10]
let b = [3; 5; 7]
let intersection = Set.intersect (Set.ofList a) (Set.ofList b)
let difference = (Set.ofList a) - (Set.ofList b)
You can then of course convert back the results into lists using Set.toList, if you wish.
As Mehrdad points out, this can be done alternatively using LINQ (or even the HashSet class in the BCL), but the approach here would seem to be most in the spirit of the F# language (certainly the nicest syntactically, and probably the most efficient too).

Slightly more compact:
let a = set [0;1;2;3]
let b = set [2;3;4;5]
let c = a - b
let d = b - a
let e = Set.intersect a b
let f = a + b
>
val c : Set<int> = seq [0; 1]
val d : Set<int> = seq [4; 5]
val e : Set<int> = seq [2; 3]
val f : Set<int> = seq [0; 1; 2; 3; ...]
Danny

Not very F#-y way I know of. You can always resort to .NET libraries. seq<T> is just IEnumerable<T>, nothing special:
let diff = System.Linq.Enumerable.Except(seq1, seq2); // seq1 - seq2
let intersect = System.Linq.Enumerable.Intersect(seq1, seq2);
let symdiff = System.Linq.Enumerable.Union(System.Linq.Enumerable.Except(seq1, seq2), System.Linq.Enumerable.Except(seq2, seq1));

Related

Can I directly use a tuple as an Array2D index in F#?

Lets say I have an the following Array2D
> let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
> printfn "%A" arr
[[2; 3; 4]
[4; 6; 8]]
I know I can access an array element like so
> arr[1, 2];;
8
But what if I have the coordinates saved in a tuple. Why can't I do the following or something similar:
> let coord = (1, 2);;
> arr[coord]
Error: input.fsx (2,1)-(2,11) typecheck error This expression was expected to have type
''a[]'
but here has type
'int[,]'
It feels kinda stupid to unpack the tuple each time before using it. Or is this the only way?
> let x, y = coord;;
> arr[x, y];;
8
You could always use ||> to unpack the tuple rather than using let expressions, along with Array2D.get. The downside is that its a lil more verbose for sure.
- let arr = Array2D.init 2 3 (fun i j -> (i+1) * (j+2))
- let coord = (1,2)
- coord ||> Array2D.get arr;;
val it : int = 8
I don't think there's any direct way to index a 2D array using a tuple. One similar alternative is to use a Map instead:
let map =
seq {
for i = 0 to 1 do
for j = 0 to 2 do
yield (i, j), (i+1) * (j+2)
} |> Map
let coord = (1, 2)
map[coord] // 8
F# treats tupled arguments in a special way. If method is defined not in F#, then it's arguments should be tupled:
System.String.Join(", ", [|1; 2; 3|])
System.String.Join ", " [|1; 2; 3|] // not valid
It's done to help overload resolution.
What you can do is to extend multidimensional array type:
type ``[,]``<'a> with
member inline ar.Item with get ((x, y): (int*int)) : 'a =
ar.[x, y]
And then use it:
let coord = (1, 2)
arr.Item coord |> printfn "%d"
Unfortunately arr.[coord] is not available and looks like a bug in compiler
All problems are solved through functions!
let xss = Array2D.init 2 3 (fun i j -> (i+1) * (j+2));;
let get arr (x,y) = Array2D.get arr x y
get xss (1,2) (* Returns 8 *)

Is there a way in f# to perform a cross operation on lists?

Is there a way in f# to perform an opreation on the all the possible element combinations of two lists in f#?
Example
l1 = [1;2;3]
l2=[4;5;6]
let plus x y = x+y
Then fun plus l1 l2 would perform [(1+4);(1+5);(1+6);(2+4);(2+5);(2+6);(3+4);(3+5);(3+6)]
Hence the output: [5;6;7;6;7;8;7;8;9]
Note: I have tried using zip but it only takes each element once.
Yep, easiest way is to use a list comprehension.
let t1 = [1;2;3]
let t2 = [4;5;6]
[for a in t1 do for b in t2 do yield a+b] //val it : int list = [5; 6; 7; 6; 7; 8; 7; 8; 9]
//as a function
let f lst1 lst2 = [for a in lst1 do for b in lst2 do yield a+b]
Another possibility is to combine a List.collect with a List.map:
let l1 = [1;2;3]
let l2 = [4;5;6]
l1 |> List.collect (fun x -> List.map ((+) x) l2) //output: [5; 6; 7; 6; 7; 8; 7; 8; 9]

Does F# have a foldList function?

Mathematica and perhaps other languages have a foldList function. It is very much like fold but instead of returning only the final computed value it returns every intermediate value.
It is not hard to write a foldList function in F#:
let foldList f (x: 'S) (m: list<'T>) =
let fs (xs: list<'S>) (y: 'T) = (f (Seq.head xs) y)::xs
List.fold fs [x] m
|> List.rev
let m = [1; 2; -3; 5]
foldList (+) 0 m
// val it : int list = [0; 1; 3; 0; 5]
List.fold (+) 0 m
// val it : int = 5
Is there such a function in F#?
If not, is there a more efficient implementation than the one above?
Is there a way to avoid the call to List.rev?
Yes, this is a built-in function, it's called List.scan:
let m = [1; 2; -3; 5]
List.scan (+) 0 m;;
//val it : int list = [0; 1; 3; 0; 5]
To answer your question about reversing the list, the implementation in FSharp.Core avoids reversing the list by using mutation. This mutable API is not exposed publicly. You can find the source code here if you're interested.

F# solution for Store Credit

I want to solve this excercise: http://code.google.com/codejam/contest/351101/dashboard#s=p0 using F#.
I am new to functional programming and F# but I like the concept and the language a lot. And I love the codejam excercise too it looks so easy but real life. Could somebody point me out a solution?
At the moment I have written this code which is just plain imperative and looks ugly from the functional perspective:
(*
C - Credit
L - Items
I - List of Integer, wher P is single integer
How does the data look like inside file
N
[...
* Money
* Items in store
...]
*)
let lines = System.IO.File.ReadAllLines("../../../../data/A-small-practice.in")
let CBounds c = c >= 5 && c <= 1000
let PBounds p = p >= 1 && p <= 1000
let entries = int(lines.[0]) - 1
let mutable index = 1 (* First index is how many entries*)
let mutable case = 1
for i = 0 to entries do
let index = (i*3) + 1
let C = int(lines.[index])
let L = int(lines.[index+1])
let I = lines.[index+2]
let items = I.Split([|' '|]) |> Array.map int
// C must be the sum of some items
// Ugly imperative way which contains duplicates
let mutable nIndex = 0
for n in items do
nIndex <- nIndex + 1
let mutable mIndex = nIndex
for m in items.[nIndex..] do
mIndex <- mIndex + 1
if n + m = C then do
printfn "Case #%A: %A %A" case nIndex mIndex
case <- case + 1
I would like to find out items which add up to C value but not in a usual imperative way - I want functional approach.
You don't specify how you would solve the problem, so it's hard to give advices.
Regarding reading inputs, you can express it as a series of transformation on Seq. High-order functions from Seq module are very handy:
let data =
"../../../../data/A-small-practice.in"
|> System.IO.File.ReadLines
|> Seq.skip 1
|> Seq.windowed 3
|> Seq.map (fun lines -> let C = int(lines.[0])
let L = int(lines.[1])
let items = lines.[2].Split([|' '|]) |> Array.map int
(C, L, items))
UPDATE:
For the rest of your example, you could use sequence expression. It is functional enough and easy to express nested computations:
let results =
seq {
for (C, _, items) in data do
for j in 1..items.Length-1 do
for i in 0..j-1 do
if items.[j] + items.[i] = C then yield (i, j)
}
Seq.iteri (fun case (i, j) -> printfn "Case #%A: %A %A" case i j) results

Check if an element is within a sequence

how to check if an element is contained within a sequence? I expected some Seq.contains, but i could not find it. Thanks
EDIT:
Or, for an easier task, how to make the diff between two sequences? Like, getting all the elements within a list that doesn not belong to another (or that do)?
Little bit simpler:
let contains x = Seq.exists ((=) x)
Seq.exists
let testseq = seq [ 1; 2; 3; 4 ]
let equalsTwo n = (n = 2)
let containsTwo = Seq.exists equalsTwo testseq
Set is your friend here:
let a = set [0;1;2;3]
let b = set [2;3;4;5]
let c = a - b
let d = b - a
let e = Set.intersect a b
let f = a + b
>
val c : Set<int> = seq [0; 1]
val d : Set<int> = seq [4; 5]
val e : Set<int> = seq [2; 3]
val f : Set<int> = seq [0; 1; 2; 3; ...]
Danny
Seq.exists again, but with slightly different syntax -
let testseq = seq [ 1; 2; 3; 4 ]
let testn = 2
testseq |> Seq.exists (fun x -> x = testn)
See MSDN F#: Seq.exists function: https://msdn.microsoft.com/en-us/library/ee353562.aspx
Lots of other good ones there too!
(Another question, another answer.)
This works, but I don't think that it's the most idomatic way to do it - (you'll need to wait until the US wakes up to find out):
let s1 = seq [ 1; 2; 3; 4 ]
let s2 = seq [ 3; 4; 5; 6 ]
seq {
for a in s1 do
if not (Seq.exists (fun n -> n = a) s2) then
yield a
}

Resources