I have to turn my variable seq<string * seq<string>> into a seq<string * string>.
I have the following data
[
("hello", ["1";"2";"3";"4"]);
("hello2", ["2";"5";"3";"9"]);
("hello3", ["1";"12";"35";"46"])
]
What I need is:
[
("hello", "1");
("hello", "2");
("hello", "3");
("hello", "4");
("hello2", "2");
("hello2", "5");
("hello2", "3");
("hello2", "9");
("hello3", "1");
("hello3", "12");
("hello3", "35");
("hello3", "46")
]
Is it feasible with a single function?
I think you're looking for Seq.collect:
yourList
|> Seq.collect (fun (s, subList) ->
subList |> Seq.map(fun (str) -> (s, str))
)
As a side note, you used the word "unboxing" wrongly in your question. In .net, boxing and unboxing have another meaning
An alternative to Seq.collect is to use list expressions:
[ for first, subElements in yourList do
for second in subElements do
yield first, second ]
Related
I wanted to group the data such that it contains list where the first element is some distinct item(like key) and the second element should be a list of tuple where first element is a key.
For example: if the list with return type (string * (string list * int)) list is
[("key1",(["data1";"data2"],1));("key1",(["data3";"data4"],10))]
then the output should be returning (string * (string list * int) list) list
[("key1",[(["data1";"data2"],1);(["data3";"data4"],10)])]
let datat= [("a",(["a";"k"],5));("b",(["b";"z"],6));("a",(["a";"y"],7));("c",(["c";"k"],2))];;`
The output should be
[("a",[(["a";"k"],5);(["a";"y"],7)]);("b",[(["b";"z"],6)]);("c",[(["c";"k"],2)])]
I tried:
datat |> List.map (fun (a,b) ->a,b );;
I could not obtain the desired output.I tried many times but i failed.Thank you for help in advance
I think you are trying to group your items by the first item of your tuples.
So you will to do datat |> List.groupBy fst
This will give you the grouping you are expected.
[("a", [("a", (["a"; "k"], 5)); ("a", (["a"; "y"], 7))]);
("b", [("b", (["b"; "z"], 6))]); ("c", [("c", (["c"; "k"], 2))])]
Then you want to clear the items from each grouped entry from their previous header. So you will map with a function taking only the second part of the tuple. List.map (fun (groupKey, groupedItems) -> groupKey, groupedItems |> List.map snd)
So the whole line is datat |> List.groupBy fst |> List.map (fun (groupKey, groupedItems) -> groupKey, groupedItems |> List.map snd)
And it will returns
[("a", [(["a"; "k"], 5); (["a"; "y"], 7)]); ("b", [(["b"; "z"], 6)]);
("c", [(["c"; "k"], 2)])]
Say I have this:
let coor = seq { ... }
// val coor : seq<int * int> = seq[(12,34); (56, 78); (90, 12); ...]
I'm trying to get the value of the first number of the second element in the sequence, in this case 56. Looking at the MSDN Collection API reference, Seq.nth 1 coor returns (56, 78), of type seq <int * int>. How do I get 56 out of it?
I suggest you go through Tuple article:
http://msdn.microsoft.com/en-us/library/dd233200.aspx
A couple of exceptions that might shed some light on the problem:
Function fst is used to access the first element of the tuple:
(1, 2) |> fst // returns 1
Function snd is used to access the second element
(1, 2) |> snd // returns 2
In order to extract element from wider tuples you can use following syntax:
let _,_,a,_ = (1, 2, 3, 4) // a = 3
To use it in various collections (well lambdas that are passed to collection's functions), let's start with following sequence:
let s = seq {
for i in 1..3 do yield i,-i
}
We end up with
seq<int * int> = seq [(1, -1); (2, -2); (3, -3)]
Let's say we want to extract only the first element (note the arguments of the lambda):
s |> Seq.map (fun (a, b) -> a)
Or even shorter:
s |> Seq.map fst
And lets finally go back to your question.
s |> Seq.nth 1 |> fst
It's a tuple, so you could use the function fst;
> let value = fst(Seq.nth 1 coor);;
val value : int = 56
...or access it via pattern matching;
> let value,_ = Seq.nth 1 coor;;
val value : int = 56
I am trying F# and trying to make a map reduce for a list of words to a word, count.
Here's what I have so far,
let data1 = ["Hello"; "Hello"; "How"; "How"; "how"; "are"]
let map = data1 |> List.map (fun x -> (x, 1))
printfn "%A" map
which gives the following output:
val map : (string * int) list =
[("Hello", 1); ("Hello", 1); ("How", 1); ("How", 1); ("how", 1); ("are", 1)]
but
let reduce = ...???
Now I am confused to how design a reduce function so that it has the word, count pair list. Any suggestions? I appreciate your help! Thanks
There's a built-in function for that:
data1 |> Seq.countBy id
which will give you a sequence of tuples:
val it : seq<string * int> =
seq [("Hello", 2); ("How", 2); ("how", 1); ("are", 1)]
The id function is another built-in function that takes a value and returns the same value, so in this case it means that you count by the strings themselves.
If you rather want a list than a seq, you can use Seq.toList:
> data1 |> Seq.countBy id |> Seq.toList;;
val it : (string * int) list =
[("Hello", 2); ("How", 2); ("how", 1); ("are", 1)]
If you want a map, this is also easy:
> data1 |> Seq.countBy id |> Map.ofSeq;;
val it : Map<string,int> =
map [("Hello", 2); ("How", 2); ("are", 1); ("how", 1)]
You don't actually need the map list. It's simpler to directly put the list into an associative map:
let reduce x =
x |> List.fold (fun m x -> match Map.tryFind x m with
| None -> Map.add x 1 m
| Some c -> Map.add x (c+1) m)
Map.empty
Let's try it in the interpreter:
> reduce data1
val it : Map<string,int> = map [("Hello", 2); ("How", 2); ("are", 1); ("how", 1)]
There is a good explanation of how to use the reducing function fold here, and a good explanation of how to use the associative map data structure Map<'Key,'T> here.
Here is a relatively inefficient but easy to understand solution:
data1 |> Seq.groupBy id |> Seq.map (fun (a,b) -> a,Seq.length b)
essentially, do the grouping and then see how many elements are in each group.
#ildjarn pointed out an improvement, which is probably the most efficient and also even simpler:
data1 |> Seq.countBy id
I have an array like this:
let items = ["A";"B";"C";"D"]
I want to transform it into an array like this:
let result = ["AB";"AC";"AD";"BC";"BD";"CD"]
I can't find anything in the language spec that does this - though I might be searching incorrectly. I thought of Seq.Fold like this:
let result = items |> Seq.fold(fun acc x -> acc+x) ""
but I am getting "ABCD"
Does anyone know how to do this? Will a modified CartesianProduct work?
Thanks in advance
What you have there are lists, not arrays -- lists use the [...] syntax, arrays use the [|...|] syntax.
That said, here's a simple implementation:
let listProduct (items : string list) =
items
|> List.collect (fun x ->
items
|> List.choose (fun y ->
if x < y then Some (x + y)
else None))
If you put it into F# interactive:
> let items = ["A"; "B"; "C"; "D"];;
val items : string list = ["A"; "B"; "C"; "D"]
> items |> listProduct |> Seq.toList;;
val it : string list = ["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Something like this should do it:
items
|> List.map (fun x -> items |> List.map (fun y -> (x, y)))
|> List.concat
|> List.filter (fun (x, y) -> x < y)
|> List.map (fun (x, y) -> x + y)
|> List.sort
I don't know if it's efficient for large lists, but it does produce this output:
["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Breakdown
The first step produces a list of list of tuples, by mapping items twice:
[[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D")];
[("B", "A"); ("B", "B"); ("B", "C"); ("B", "D")];
[("C", "A"); ("C", "B"); ("C", "C"); ("C", "D")];
[("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]]
Second, List.concat turns the list of list into a single list:
[("A", "A"); ("A", "B"); ("A", "C"); ("A", "D"); ("B", "A"); ("B", "B");
("B", "C"); ("B", "D"); ("C", "A"); ("C", "B"); ("C", "C"); ("C", "D");
("D", "A"); ("D", "B"); ("D", "C"); ("D", "D")]
Third, List.filter removes the tuples where the first element is equal to or larger than the second element:
[("A", "B"); ("A", "C"); ("A", "D"); ("B", "C"); ("B", "D"); ("C", "D")]
Fourth, List.map produces a list of concatenated strings:
["AB"; "AC"; "AD"; "BC"; "BD"; "CD"]
Finally, List.sort sorts the list, although in this case it's not necessary, as the list already has the correct order.
You might also consider using Seq.distinct to remove duplicates, if there are any.
You could create a function to create a list of all head/tail pairs in a list:
let rec dec = function
| [] -> []
| (x::xs) -> (x, xs) :: dec xs
or a tail-recursive version:
let dec l =
let rec aux acc = function
| [] -> acc
| (x::xs) -> aux ((x, xs)::acc) xs
aux [] l |> List.rev
you can then use this function to create your list:
let strs (l: string list) = l |> dec |> List.collect (fun (h, t) -> List.map ((+)h) t)
I'd do it like this:
let rec loop = function
[] -> []
| x :: xs -> List.map ((^) x) xs # loop xs
This has the advantage of not building every pair of elements from the list only to discard half. (I'll leave getting rid of the append as an exercise :-)
For me, it is a bit easier to tell what's going on here compared some of the other proposed solutions. For this kind of problem, where to process an element x you need also access to the rest of the list xs, standard combinators won't always make solutions clearer.
let items = ["A";"B";"C";"D"]
let rec produce (l: string list) =
match l with
// if current list is empty or contains one element - return empty list
| [] | [_] -> []
// if current list is not empty - match x to head and xs to tail
| x::xs ->
[
// (1)
// iterate over the tail, return string concatenation of head and every item in tail
for c in xs -> x + c
// apply produce to tail, concat return values
yield! produce xs
]
1st iteration: l = [A, B, C, D] - is not empty, in second match case we'll have x = A, xs = [B, C, D]. 'for' part of the list expression will yield [AB, AC, AD] and result of applying produce to xs.
2nd iteration:l = [B, C, D] is not empty so second match case we'll have x = B, xs = [C, D]. 'for' part of the list expression will yield [BC, BD] and result of applying produce to xs.
3rd iteration:l = [C, D] is not empty in second match case we'll have x = C, xs = [D]. 'for' part of the list expression will yield [CD] and result of applying produce to xs.
4th iteration:l = [D] contains one element -> return empty list.
Final result will be concatenation of [AB, AC, AD] ++ [BC, BD] ++ [CD]
This is an apt motivating example for implementing a List monad in F#. Using F# computation expressions, we get:
type ListMonadBuilder() =
member b.Bind(xs, f) = List.collect f xs
member b.Delay(f) = fun () -> f()
member b.Let(x, f) = f x
member b.Return(x) = [x]
member b.Zero() = []
let listM = new ListMonadBuilder()
Now, to solve the original problem we simply use our List monad.
let run = listM {
let! x = ['A' .. 'D']
let! y = List.tail [ x .. 'D']
return string x + string y
}
run();; in F# Interactive will return the desired result.
For another example of using the List monad, we can get the Pythagorean triples <= n.
let pythagoreanTriples n = listM {
let! c = [1 .. n]
let! b = [1 .. c]
let! a = [1 .. b]
if a*a + b*b = c*c then return (a, b, c)
}
Running pythagoreanTriples 10 ();; in F# interactive returns:
val it : (int * int * int) list = [(3, 4, 5); (6, 8, 10)]
What is the best way to map the following:
[|"A"; "B"; "C"; "D"|]
to
[|("","A","B"); ("A","B","C"); ("B","C","D"); ("C","D","")|]
?
I'd prefer approach based on idiomatic combinators: attach an empty string to both ends of array, use Seq.windowed 3 to produce sequence of sliding arrays of three items, and finally map each sequence element into tuple and convert sequence back to array:
let conv source =
Array.concat [[|String.Empty|]; source; [|String.Empty|]] |> Seq.windowed 3
|> Seq.map (fun x -> x.[0],x.[1],x.[2]) |> Seq.toArray
Testing conv [|"A";"B";"C";"D"|] under FSI yields:
val it : (string * string * string) [] =
[|("", "A", "B"); ("A", "B", "C"); ("B", "C", "D"); ("C", "D", "")|]
I would do this:
let neighbors (xs: _ []) =
let get i = if i>=0 && i<xs.Length then xs.[i] else ""
Array.mapi (fun i x -> get(i-1), x, get(i+1)) xs
This is the first time I've looked at f# so pardon my attempt if it isn't correct. I also don't have f# so I can't test this. But based on Array.map...
let data = [|"A"; "B"; "C"; "D"|]
let convert = data |> Array.map (fun x -> (char(int x - 1), x, char(int x + 1)))
printfn "Converting to tupels by using map = %A" convert
Hopefully it will point you in the right direction.