Given this:
[
("A","A122");
("A","A123");
("B","B122");
("B","B123");
("C","C122");
]
Is there a standard function to get this?
[
("A",["A122";"A123"]);
("B",["B122";"B123"]);
("C",["C122"])
]
I thought of Seq.distinctBy, List.partition, Set, Map, but none of them seem to be what I'm looking for.
Thanks... while I'm waiting, I'll try to roll my own :)
Silly me, I didn't notice Seq.groupBy!
[
("A","A122");
("A","A123");
("B","B122");
("B","B123");
("C","C122");
]
|> Seq.groupBy (fun (a, b) -> a)
|> Seq.map (fun (a, b) -> (a, Seq.map snd b))
Output :
seq
[("A", seq ["A122"; "A123"]); ("B", seq ["B122"; "B123"]);
("C", seq ["C122"])]
For O(1) lookup:
[
("A","A122");
("A","A123");
("B","B122");
("B","B123");
("C","C122");
]
|> Seq.groupBy fst
|> dict
Related
How do I identify the max length from a Map's value set?
let numbers = [1;2;2;3;3;3;4;5;5]
let map = numbers |> Seq.groupBy id
|> Map.ofSeq
I want to do this:
map.Values |> List.max
or...
let longestSequence = Map.map (fun (k, v) -> List.max(List.ofSeq(v)));
you can get something similar to Dictionary.Values with Map.toSeq >> Seq.map snd so you can get the largest collected sequence in your map like this:
> map |> Map.toSeq |> Seq.map snd |> Seq.maxBy Seq.length;;
val it : seq<int> = seq [3; 3; 3]
of course when your list is already in a sorted stage it seems strange to take the detour over Map as
> numbers |> Seq.groupBy id |> Seq.map snd |> Seq.maxBy Seq.length;;
val it : seq<int> = seq [3; 3; 3]
will do the same ;)
also if you think about the problem here can write a List.fold (with a additional map of the result) doing this as well which will only require to traverse the (sorted) list once ... maybe you can try to do this yourself ^^
There are three different seq of same size
a:int = {1, 2, 3, 4}
b:string= {"a","b","a","d"}
c:string= {"y","y","t","t"}
how can I create a new seq from seq:a with condition
where b="a" and c="y"
Seq.zip3 a b c
|> Seq.choose (function (n, "a", "y") -> Some n | _ -> None)
Seq.zip a (Seq.zip b c)
|> Seq.filter (snd >> ((=) ("a", "y")))
|> Seq.map fst
Hi I m trying to expand a seq.groupby function. On a single argument this works and was discussed here before here, key code repeated:
let group_fold key value fold acc seq =
seq |> Seq.groupBy key
|> Seq.map (fun (key, seq) -> (key, seq |> Seq.map value |> Seq.fold fold acc))
let tuples = [("A",12); ("A",10); ("B",1); ("C",2); ("C",1)]
let regular = group_fold fst snd (+) 0 tuples
let piped = tuples |> group_fold fst snd (+) 0
I would like to do the same but with multiple grouping arguments. This is what I tried:
let tuples = [("A", "B", "C", 12); ("A", "B", "C", 10); ("B","B","B",1); ("C","B","B",2); ("C","B","B", 1)]
let group_fold key1 key2 key3 value fold acc seq =
seq |> Seq.groupBy (key1 & key2 & key3)
|> Seq.map (fun (key1, key2, key3, seq) -> (key1, key2, key3, seq |> Seq.map value |> Seq.fold fold acc))
let piped = tuples |> group_fold fst snd trd fth (+) 0
This groupby multiple items does not seem to work. i know in c# I would do sth like this:
tuples.GroupBy(a => new { a.fst, a.snd, a.trd})
How can I do this in Fsharp?
Like this:
let group_fold keys value fold acc seq =
seq |> Seq.groupBy keys
|> Seq.map (fun ((key1, key2, key3), seq) ->
(key1, key2, key3, seq |> Seq.map value |> Seq.fold fold acc))
let piped = tuples |> group_fold (fun (k1, k2, k3, _) ->
k1, k2, k3) (fun (_, _, _, v) -> v) (+) 0
I have a set of data of arrays of arrays. As an example
[[1,3],
[4,3],
[1,2],
[7,2]]
I'd like to transform this to
[(3,[1,4])
(2,[1,7])]
that is: create an array of tuples, where the first member is from index 1 of the original and the array is all the values of index 0 from the original grouped based on index 1. I can solve this imperatively but would like to do it in a more FP kind of way
Use Seq.groupBy in combination with a few maps will get the desired result
[[1;3];
[4;3];
[1;2];
[7;2]]
|> Seq.groupBy (fun (a::b) -> b)
|> Seq.map (fun (a,b) -> a,b|> Seq.toList)
|> Seq.map (fun (a,b) -> a,b|>List.map (fun (c::d) -> c ))
F# is a statically typed functional programming language so the first thing you want to do is convert your input into a typeful representation such as a list of pairs of ints:
[ 1, 3
4, 3
1, 2
7, 2 ]
Then you can pipe it through the Seq.groupBy function using the snd function to key on the second element of each pair:
|> Seq.groupBy snd
This gives you [3, [1, 3; 4, 3]; ...] etc. so you want to map over the right hand sides extracting just the values (i.e. stripping out the keys) using the fst function:
|> Seq.map (fun (k, kvs) -> k, Seq.map fst kvs)
This gives your desired answer: [(3, [1; 4]); (2, [1; 7])].
Similar to #John's answer, but assume that inner collections are arrays with at least two elements:
[|[|1; 3|];
[|4; 3|];
[|1; 2|];
[|7; 2|]|]
|> Seq.map (fun arr -> arr.[0], arr.[1])
|> Seq.groupBy snd
|> Seq.map (fun (k, v) -> k, Seq.map fst v)
// val it : seq<int * seq<int>> = seq [(3, seq [1; 4]); (2, seq [1; 7])]
My answer is not essentially different to the answers above, but it uses a bit of combinatory logic, so it looks more idiomatic (to me). Also, it has some validity check.
Apply2 is essentially an S combinator.
let data =
[[1;3];
[4;3];
[1;2];
[7;2]]
// Apply2 operator applies two functions to x
// and returns both results as a tuple
let (.&.) f g x = f x, g x
// A naive validator for sequences
let assert' predicate message xs =
if not <| Seq.forall predicate xs then
failwith message
xs
let aggregate data =
data
// validate the input
|> assert' (List.length >> (=) 2) "All elements must be of length of two"
// essentially, convert a 2-element list to a tuple
|> Seq.map (List.head .&. (List.tail >> List.head))
// group over the second element of a tuple
|> Seq.groupBy snd
// we no longer need the key element in a tuple, so remove it
|> Seq.map (fst .&. (snd >> Seq.map fst))
aggregate data |> printf "%A"
Let's say I have a sequence of sequences, e.g.
{1, 2, 3}, {1, 2, 3}, {1, 2, 3}
What is the best way to pivot or zip this sequence so I instead have,
{1, 1, 1}, {2, 2, 2}, {3, 3, 3}
Is there a comprehensible way of doing so without resorting to manipulation of the underlying IEnumerator<_> type?
To clarify, these are seq<seq<int>> objects. Each sequences (both internal and external) can have any number of items.
If you're going for a solution which is semantically Seq, you're going to have to stay lazy all the time.
let zip seq = seq
|> Seq.collect(fun s -> s |> Seq.mapi(fun i e -> (i, e))) //wrap with index
|> Seq.groupBy(fst) //group by index
|> Seq.map(fun (i, s) -> s |> Seq.map snd) //unwrap
Test:
let seq = Enumerable.Repeat((seq [1; 2; 3]), 3) //don't want to while(true) yield. bleh.
printfn "%A" (zip seq)
Output:
seq [seq [1; 1; 1]; seq [2; 2; 2]; seq [3; 3; 3]]
This seems very inelegant but it gets the right answer:
(seq [(1, 2, 3); (1, 2, 3); (1, 2, 3);])
|> Seq.fold (fun (sa,sb,sc) (a,b,c) ->a::sa,b::sb,c::sc) ([],[],[])
|> fun (a,b,c) -> a::b::c::[]
It looks like matrix transposition.
let data =
seq [
seq [1; 2; 3]
seq [1; 2; 3]
seq [1; 2; 3]
]
let rec transpose = function
| (_::_)::_ as M -> List.map List.head M :: transpose (List.map List.tail M)
| _ -> []
// I don't claim it is very elegant, but no doubt it is readable
let result =
data
|> List.ofSeq
|> List.map List.ofSeq
|> transpose
|> Seq.ofList
|> Seq.map Seq.ofList
Alternatively, you may adopt the same method for seq, thanks to this answer for an elegant Active pattern:
let (|SeqEmpty|SeqCons|) (xs: 'a seq) =
if Seq.isEmpty xs then SeqEmpty
else SeqCons(Seq.head xs, Seq.skip 1 xs)
let rec transposeSeq = function
| SeqCons(SeqCons(_,_),_) as M ->
Seq.append
(Seq.singleton (Seq.map Seq.head M))
(transposeSeq (Seq.map (Seq.skip 1) M))
| _ -> Seq.empty
let resultSeq = data |> transposeSeq
See also this answer for technical details and two references: to PowerPack's Microsoft.FSharp.Math.Matrix and yet another method involving mutable data.
This is the same answer as #Asti, just cleaned up a little:
[[1;2;3]; [1;2;3]; [1;2;3]]
|> Seq.collect Seq.indexed
|> Seq.groupBy fst
|> Seq.map (snd >> Seq.map snd);;