Seq.cast tuple values from obj to string - casting

What is the nice and working way of doing a cast like this?
seq { yield (box "key", box "val") }
|> Seq.cast<string*string>
Since this looks extremely ugly:
seq { yield (box "key", box "val") }
|> Seq.map (fun (k,v) -> k.ToString(), v.ToString())
As well as this:
seq { yield (box "key", box "val") }
|> Seq.map (fun (k,v) -> unbox<string>(k), unbox<string>(v))
Is there a way to "unbox" a tuple into another tuple?

You could write it slightly nicer as:
seq { yield (box "key", box "val") }
|> Seq.map (fun (k, v) -> string k, string v)
Imagine, however, that you have a Tuple2 module:
module Tuple2 =
// ... other functions ...
let mapBoth f g (x, y) = f x, g y
// ... other functions ...
With such a mapBoth function, you could write your cast as:
seq { yield (box "key", box "val") } |> Seq.map (Tuple2.mapBoth string string)
There's no Tuple2 module in FSharp.Core, but I often define one in my projects, containing various handy one-liners like the one above.

Related

How to declare a piped list in a Enum inside another Enum?

I'm trying to use a piped list in a Enum inside another Enum. To try to make myself a little bit more clear, bellow is my code:
def word_count(str) do
String.downcase(str)
|> String.split
|> Enum.map(fn x -> Enum.count(LIST HERE, x) end)
end
So what I want to do is to use the piped list as a parameter in the Enum.count
If you are on the modern enough elixir (as you should be,) then/2 is your friend.
"Foo bar foo"
|> String.downcase()
|> String.split()
|> then(&Enum.map(&1, fn x -> Enum.count(&1, fn y -> y == x end) end))
#⇒ [2, 1, 2]
The most readable solution would still be
words =
"Foo bar foo"
|> String.downcase()
|> String.split()
Enum.map(words, &Enum.count(words, fn x -> x == &1 end))
One should not try to keep a single pipe despite readability.
The Enum functions take an enumerable as their first argument, so you can simply pipe a list into them.
If you want to count how many times each word appears, you can use Enum.frequencies/1:
def word_count(str) do
str
|> String.downcase()
|> String.split()
|> Enum.frequencies()
end
Example:
iex> Example.word_count("foo bar baz")
%{"bar" => 1, "baz" => 1, "foo" => 1}
In this case Enum.frequencies/1 was helpful, but often you can use Enum.reduce/3 to write your own logic. Here is Enum.frequencies/1 replaced with Enum.reduce/3 that does the same thing:
def word_count(str) do
str
|> String.downcase()
|> String.split()
|> Enum.reduce(%{}, fn word, acc ->
Map.update(acc, word, 1, fn count -> count + 1 end)
end)
end
In response to the comments, using Kernel.then/1, with the disclaimer that there is probably a better way to do this depending on what is desired (like reduce above, or using comprehensions):
1..10
|> then(fn one_to_ten ->
Enum.map(one_to_ten, fn x ->
Enum.map(one_to_ten, fn y ->
{x, y}
end)
end)
end)

Concatenating lists of lists in F#

From pseudo C#, I have this:
class C
{
List<A> a;
List<B> b;
}
List<C> L;
I would like to get to get two lists: ListA and ListB where ListA is the concatenation of all 'a' fields from the list L, and similar for ListB.
it would be something like:
var ListA = new List<A>();
var ListB = new List<B>();
foreach (var l in L)
{
ListA.Append(l.a);
ListB.Append(l.b);
}
In F#,
I assume it would be something like: let ListA = L |> List.Concat (but how do I say to pick the field a?)
or could it be done as a let ListA = L |> List.Fold (fun acc value -> acc.Concat value) (how do I specify the empty list here?)
or, can it be done like this?
let getElementsA (l : C list) =
seq {
for element in l do
for a in element.a do
yield a
}
but isn't that too verbose?
This is what List.collect, or Seq.collect for C# lists, is for:
let listA = l |> Seq.collect (fun element -> element.a) |> List.ofSeq
let listB = l |> Seq.collect (fun element -> element.b) |> List.ofSeq
Or if you really need to do it in one iteration you can use a fold:
let (seqA, seqB) =
l |> Seq.fold
(fun (seqA, seqB) element -> (Seq.append element.a seqA, Seq.append element.b seqB))
([], [])
You can use List.collect:
let getElementsA (cs : C list) = cs |> List.collect (fun c -> c.a)
if the property type is System.Collection.List<T> then you can use Seq.collect:
let getElementsA (cs : C list) = cs |> Seq.collect (fun c -> c.AS)
this returns a A seq which you can convert into a list using List.ofSeq:
let getElementsA (cs : C list) = cs |> Seq.collect (fun c -> c.AS) |> List.ofSeq
F# uses other lists, function objects (like delegates). You can find all that you need in Microsoft.FSharp namespace
If I have this code in F#.
A function that resives a list with action and return nothing (list:'a list -> action:('a -> unit) -> unit).
module FS =
let actLit list action =
list
|> List.iter (action)
For this on C#, include Microsoft.FSharp.Collections.ListModule module and call functions work with F# lists. ListModule.OfSeq(l) creates new F# list.
Microsoft.FSharp.Core.FunctionModule contains conversion methods.
After converting you can call it.
var a = new List<int> ();
var list = ListModule.OfSeq(a);
var func = FuncConvert.FromAction<int>(Console.WriteLine);
FS.actLit(list, func);

Adding no value to return list

I'm having a problem with understanding how F# works. I come from C# and I think that I'm trying to make F# work like C#. My biggest problem is returning values in the correct format.
Example:
Let's say I have function that takes a list of integers and an integer.
Function should print a list of indexes where values from list match passed integer.
My code:
let indeks myList n = myList |> List.mapi (fun i x -> if x=n then i else 0);;
indeks [0..4] 3;;
However it returns:
val it : int list = [0; 0; 0; 3; 0]
instead of just [3] as I cannot ommit else in that statement.
Also I have targeted signature of -> int list -> int -> int list and I get something else.
Same goes for problem no. 2 where I want to provide an integer and print every number from 0 to this integer n times (where n is the iterated value):
example:
MultiplyValues 3;;
output: [1;2;2;3;3;3]
Best I could do was to create list of lists.
What am I missing when returning elements?
How do I add nothing to the return
example: if x=n then n else AddNothingToTheReturn
Use List.choose:
let indeks lst n =
lst
|> List.mapi (fun i s -> if s = n then Some i else None)
|> List.choose id
Sorry, I didn't notice that you had a second problem too. For that you can use List.collect:
let f (n : int) : list<int> =
[1 .. n]
|> List.collect (fun s -> List.init s (fun t -> s))
printfn "%A" (f 3) // [1; 2; 2; 3; 3; 3]
Please read the documentation for List.collect for more information.
EDIT
Following s952163's lead, here is another version of the first solution without the Option type:
let indeks (lst : list<int>) (n : int) : list<int> =
lst
|> List.fold (fun (s, t) u -> s + 1, (if u = n then (s :: t) else t)) (0, [])
|> (snd >> List.rev)
This one traverses the original list once, and the (potentially much shorter) newly formed list once.
The previous answer is quite idiomatic. Here's one solution that avoids the use of Option types and id:
let indeks2 lst n =
lst
|> List.mapi (fun i x -> (i,x))
|> List.filter (fun x -> (fst x) % n = 0 )
|> List.map snd
You can modify the filter function to match your needs.
If you plan to generate lots of sequences it might be a good idea to explore Sequence (list) comprehensions:
[for i in 1..10 do
yield! List.replicate i i]
If statements are an expression in F# and they return a value. In this case both the IF and ELSE branch must return the same type of value. Using Some/None (Option type) gets around this. There are some cases where you can get away with just using If.

F# List.mapi function with filtering

I have a line of code like this:
list |> List.mapi (fun i x -> y, i)
(Assume that y is already defined type)
But I want to return elements with some condition (e.g filter it)
I am not able to write like this:
list |> List.mapi (fun i x -> if 'condition' then y, i)
because it needs else condition as well and I don't have 'else' case.
I also didn't manage to use filter at the same time, because I need to return correct indexes as well, and if I filter the list, indexes will be changed.
Any ideas?
EDIT
By now, I implemented like this:
list |> List.mapi (fun i a -> if (a = None) then O, i else X, i) |> List.filter (fun (a,i) -> a = O)
I'm giving useless X,i for else case, just to be able to write condition after that and remove X ones. It's working, that's the result I want. But I'm sure there is a better solution.
Let me add yet another answer:
From your question and comments I understand that you want to filter a list by a condition depending on the values while retaining the original indexes.
I'm not sure whether the result should then consist of a list of fixed values and original index or you want to map. The following allows both:
let indexedFilterMap p f =
List.indexed
>> List.filter (snd >> p)
>> List.map (fun (i, x) -> f x, i)
add index
filter by p using second values of indexed list, i.e. original values
map the remaining values and reverse the order in the tuple (s.t. it is value, index)
If you need the index for the mapping (as the question title includes mapi):
let indexedFilterMapi p f =
List.indexed
>> List.filter (snd >> p)
>> List.map f
Or if you need the index for the filter:
let indexedFilteriMap p f =
List.indexed
>> List.filter p
>> List.map (fun (i, x) -> f x, i)
The combination should be straightforward.
These can then be used:
let list = ['a'; 'b'; 'c']
let condition = (<>) 'b'
let y = "fixed value"
indexedFilterMap condition (fun _ -> y) list // [("fixed value", 0); ("fixed value", 2)]
let m (i, _) = sprintf "fixed value %i" i
indexedFilterMapi condition m list // ["fixed value 0"; "fixed value 2"]
let c (i, _) = i <> 1
indexedFilteriMap c (fun _ -> y) list // [("fixed value", 0); ("fixed value", 2)]
If you want to filter, but have indexes applied in strictly monotonically increasing order after filtering, then filter first, and then add the index values:
list |> List.filter condition |> List.mapi (fun i x -> x, i)
Here's an example where b is filtered away from an alphabetical list of characters:
[('a', 0); ('c', 1); ('d', 2); ('e', 3); ('f', 4); ('g', 5); ('h', 6);
('i', 7); ('j', 8); ('k', 9); ('l', 10); ('m', 11); ('n', 12); ('o', 13)]
First of all, be aware that looking up by i from a list is an O(n) operation so if that's what you're doing, there could be a more efficient alternative available by expressing the problem differently.
For the problem as described, you could do something like this:
list
|> List.mapi (fun i x -> x, i)
|> List.choose (fun (x,i) -> if 'condition on x' then Some (y,i) else None)
Returns a list of tuples of y and an element index that satisfied the condition.
Example:
Consider I start with ['a','b','c','d','e'], the first mapi maps the list to [('a',0),('b',1),('c',2),('d',3),('e',4)] then I apply choose with (for example) a condition that select vowels and returns some value y. I end up with [(y,4)].
Edit: In response to your update, here is an example of using this in precisely the way you want.
list
|> List.mapi (fun i x -> x, i)
|> List.choose (fun (x,i) ->
match x with
|O -> Some (O, i)
|X -> None)
There are many ways to achieve this, if you use sequence expressions you don't need to write the else branch:
let list = ['a';'b';'c';'d';'e']
let condition x = x % 2 = 0
[for i = 0 to List.length list - 1 do
if condition i then yield (i, list.[i])]
// val it : (int * char) list = [(0, 'a'); (2, 'c'); (4, 'e')]
But be aware that traversing the list by index is not efficient in a long list. So, it depends what are you looking for, if performance is a must I would use List.fold instead:
list
|> List.fold (fun (i, acc) e -> (i + 1, if condition i then (i, e)::acc else acc)) (0, [])
|> snd
|> List.rev // if you care about the order

F# find in list of records the records with same id and add up their values

Iam an F# newbie, I have following starting point:
type aB = { ID: int; Slide: list<string * int> }
// examples of aB's
let aB1 = { ID = 1; Slide = [("-10%",-20); ("0%",0); ("10%",20)] }
let aB2 = { ID = 2; Slide = [("-10%",6); ("0%",0); ("10%",3)] }
let correctoraB2 = {ID = 2; Slide = [("-10%", -2); ("0%", 0); ("10%", -1)] }
// Now we bunch the aB`s in a list together
let bunchedABRaw = [aB1; aB2; correctoraB2]
This list can now become quite long, in this list, I need now to first identify all the aB's with identical ID's, then I want to net out their slides, so that a new list results
let bunchedABReduced = [aB1; aB2New], where
aB2New = { ID = 2; Slide = [("-10%",4); ("0%",0); ("10%",2)] }
I am reading through the F# library on msdn but so far I don't know yet how to solve the problem, would be very happy for code proposition.
Thanks a lot
Martin
OK working my way through this when I have a minute.
Here's the first part where you can merge the slides of two aB's:
// this function can merge two slides
let mergeSlides l1 l2 =
List.zip l1 l2
|> List.map (fun ((a1, b1), (a2,b2)) -> (a1, b1+b2))
// see what it does
mergeSlides aB2.Slide correctoraB2.Slide
This bit groups all the aB's with the same Id:
let grp = bunchedABRaw
|> Seq.groupBy (fun a -> a.ID)
And now we can use mergeSlides as a folding function, that we use fold over each sequence of Ab's with the same Id to make the netted aB.
So here's the whole thing:
let mergeSlides l1 l2 = 
    List.zip l1 l2
    |> List.map (fun ((a1, b1), (a2,b2)) -> (a1, b1+b2))
let net =
bunchedABRaw
|> Seq.groupBy (fun a -> a.ID)
|> Seq.map (fun (i, s) -> (i, s |> Seq.map (fun a -> a.Slide))) // strip away the slides
|> Seq.map (fun (i, s) -> (i, List.ofSeq s)) // turn seq<slide> into list<slide>
|> Seq.map (fun (i, l) -> (i, List.fold mergeSlides l.Head l.Tail)) // so we can use HEad and Tail
|> Seq.map (fun (i, l) -> {ID=i;Slide=l}) // and Project into aB
|> List.ofSeq // and then List
Enjoy!
Try this:
Set up a dictionary where the keys will be the IDs you encounter and the values will be a "netted" aB type for that ID.
Then run a fold* on the list using the dictionary as your state and have the function you fold across the list accumulate the items in the dictionary by ID ("netting" them as you go).
After that you can put all the dictionary's values into a return list.
If you can't "net" them as you go then you could store a list of items as values instead of a single "netted" value and then do the netting after the fold finishes.
*fold http://msdn.microsoft.com/en-us/library/ee353894.aspx
EDIT: Made some things clearer