Is there a way to return an object used in a lambda expression, but with a different value? I've been using the "kind of linq-select" way, but I'd like to do something like this:
let bob= tab
|> Seq.map (fun x -> ignore (x.Value=x.Value+1); x)
|> Seq.iter (fun x -> x.Dump())
making all the x's in my sequence to have their value +1'ed.
instead of doing this:
let bob= tab
|> Seq.map (fun x -> Ville(IdVille= 9, NoVille=x.Value+1, Nom=x.Nom, __RowVersion = x.__RowVersion))
|> Seq.iter (fun x -> x.Dump())
edit:
What I expect to get : from this, a dump of the sequence, hence the Iter and Dump...
What I want the sequence to be? Here is an example, well the original sequence, but after applying a function to each element and get a copy of the result... (No side effect on the original sequence).
For example, I have a sequence of names, I'd like to have a copy of the original sequence, but with upper-cased names. Now imagine the same, but with a sequence of objects got from a database.
Edit2:
I made a test with LinqPad and AdventureWorks database, and I did this:
let dc = new TypedDataContext()
let tab = dc.GetTable<Address>()
let bob = tab
|> Seq.map (fun x -> ignore (x.AddressLine1 <- "Bob"); x)
tab.Dump()
bob.Dump()
The 2 Dump() results are differents. If I invert the 2 Dump() calls, both results are the same. You were right!
It's hard to tell what you're trying to do, but mutating a value suggests an imperative approach, so why not a for loop?
for x in tab do
x.Value <- x.Value + 1
x.Dump()
What value do you expect for bob? Seq.iter returns unit. If you mutate tab within Seq.map it will have the same value as bob.
EDIT
If you modify elements of a sequence within map the result and the original sequence will be one and the same. map is not intended to be used with side effects. An example:
type T(value) =
member val Value = value with get, set
let tab = [T(0); T(1); T(3)]
let bob = tab |> Seq.map (fun x -> x.Value <- x.Value + 1; x)
tab = (Seq.toList bob) //true
You can try using map along with an object expression to update just one field:
let bob = tab
|> Seq.map (fun x -> {x with Value = x.Value + 1})
|> Seq.iter (fun x -> x.Dump())
Though bob will not get the results of Dump() assigned to it if you are using iter. You'd need to use map again for that.
Edit
This only works with record types.
Related
Let's say I have a map M:Map<int, bool> (initially empty). I want to update this time. I have a list L = [1 .. 100] and for each element in this list, I want to set the corresponding value in M false. So something like, [1 .. 100] |> List.map (fun x -> M.Add(x, false)). But M.Add() returns a new map every time and the updates are not reflected. How can I do this update in an idiomatic F# way?
You can use a fold for this:
let m = [1 .. 100]
|> List.fold( fun (acc:Map<int,bool>) x -> acc.Add(x, false)) Map.empty
A fold takes an accumulator and the current value as parameters. You can here use the Add method to return the updated Map.
For your specific scenario you may also consider a dictionary:
let m2 = [1 .. 100]
|>List.map(fun x->(x,false))
|>dict
I think I got a working solution. Instead of declaring a Map first and then updating it (which would return a new Map every time), I constructed a list first and then converted the list to a Map.
[1 .. 100]
|> List.map
(fun x ->
(x, false)
)
|> Map.ofList
I don't know if this solution is any good as I'm fairly new to F#. I'll be glad to know if this solution can be improved.
I have the following:
Map<Instrument, Map<PositionSide, PositionData>>
is there a way to flatten this to a:
PositionData list
without iterating through the 2 maps manually?
If we do not worry about duplicate values from the inner maps, it can be done by treating the maps as sequences. Their in-built GetEnumerator() method returns a sequence of the type System.Collections.Generic.KeyValuePair<_,_>.
The latter can be deconstructed by F#'s predefined active recognizer KeyValue.
Map.empty<Instrument, Map<PositionSide, PositionData>>
|> Seq.collect (fun (KeyValue(_, v)) -> v)
|> Seq.map (fun (KeyValue(_, v)) -> v)
|> Seq.toList
// val it : PositionData list = []
I'm afraid it is not possible. There are many issues with it
at first this are not 2, but potentially many collections in another collection.
Map is not built for iteration, it's dictionary like. But you can convert it to a List of pairs first with Map.toList
there is no other possibility than iterate over values if you need them all.
let toValuesList map =
map
|> Map.toList
|> List.map snd
let ds =
data
|> toValuesList
|> List.collect toValuesList
If you could lookup PositionData by some key you would at most avoid iterating internal Map's
let data =
map
|> toValuesList
|> List.map (fun valueMap -> lookupWithin valueMap)
How does one get the first key,value pair from F# Map without knowing the key?
I know that the Map type is used to get a corresponding value given a key, e.g. find.
I also know that one can convert the map to a list and use List.Head, e.g.
List.head (Map.toList map)
I would like to do this
1. without a key
2. without knowing the types of the key and value
3. without using a mutable
4. without iterating through the entire map
5. without doing a conversion that iterates through the entire map behind the seen, e.g. Map.toList, etc.
I am also aware that if one gets the first key,value pair it might not be of use because the map documentation does not note if using map in two different calls guarantees the same order.
If the code can not be written then an existing reference from a site such as MSDN explaining and showing why not would be accepted.
TLDR;
How I arrived at this problem was converting this function:
let findmin l =
List.foldBack
(fun (_,pr1 as p1) (_,pr2 as p2) -> if pr1 <= pr2 then p1 else p2)
(List.tail l) (List.head l)
which is based on list and is used to find the minimum value in the associative list of string * int.
An example list:
["+",10; "-",10; "*",20; "/",20]
The list is used for parsing binary operator expressions that have precedence where the string is the binary operator and the int is the precedence. Other functions are preformed on the data such that using F# map might be an advantage over list. I have not decided on a final solution but wanted to explore this problem with map while it was still in the forefront.
Currently I am using:
let findmin m =
if Map.isEmpty m then
None
else
let result =
Map.foldBack
(fun key value (k,v) ->
if value <= v then (key,value)
else (k,v))
m ("",1000)
Some(result)
but here I had to hard code in the initial state ("",1000) when what would be better is just using the first value in the map as the initial state and then passing the remainder of the map as the starting map as was done with the list:
(List.tail l) (List.head l)
Yes this is partitioning the map but that did not work e.g.,
let infixes = ["+",10; "-",10; "*",20; "/",20]
let infixMap = infixes |> Map.ofList
let mutable test = true
let fx k v : bool =
if test then
printfn "first"
test <- false
true
else
printfn "rest"
false
let (first,rest) = Map.partition fx infixMap
which results in
val rest : Map<string,int> = map [("*", 20); ("+", 10); ("-", 10)]
val first : Map<string,int> = map [("/", 20)]
which are two maps and not a key,value pair for first
("/",20)
Notes about answers
For practical purposes with regards to the precedence parsing seeing the + operations before - in the final transformation is preferable so returning + before - is desirable. Thus this variation of the answer by marklam
let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Value)
achieves this and does this variation by Tomas
let findmin m =
Map.foldBack (fun k2 v2 st ->
match st with
| Some(k1, v1) when v1 < v2 -> st
| _ -> Some(k2, v2)) m None
The use of Seq.head does return the first item in the map but one must be aware that the map is constructed with the keys sorted so while for my practical example I would like to start with the lowest value being 10 and since the items are sorted by key the first one returned is ("*",20) with * being the first key because the keys are strings and sorted by such.
For me to practically use the answer by marklam I had to check for an empty list before calling and massage the output from a KeyValuePair into a tuple using let (a,b) = kvp.Key,kvp.Value
I don't think there is an answer that fully satisfies all your requirements, but:
You can just access the first key-value pair using m |> Seq.head. This is lazy unlike converting the map to list. This does not guarantee that you always get the same first element, but realistically, the implementation will guarantee that (it might change in the next version though).
For finding the minimum, you do not actually need the guarantee that Seq.head returns the same element always. It just needs to give you some element.
You can use other Seq-based functons as #marklam mentioned in his answer.
You can also use fold with state of type option<'K * 'V>, which you can initialize with None and then you do not have to worry about finding the first element:
m |> Map.fold (fun st k2 v2 ->
match st with
| Some(k1, v1) when v1 < v2 -> st
| _ -> Some(k2, v2)) None
Map implements IEnumerable<KeyValuePair<_,_>> so you can treat it as a Seq, like:
let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Key)
It's even simpler than the other answers. Map internally uses an AVL balanced tree so the entries are already ordered by key. As mentioned by #marklam Map implements IEnumerable<KeyValuePair<_,_>> so:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Seq.head
// will return ("X", 1)
It doesn't matter what order the elements were added to the map, Seq.head can operate on the map directly and return the key/value mapping for the min key.
Sometimes it's required to explicitly convert Map to Seq:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Map.toSeq |> Seq.head
The error message I've seen for this case says "the type 'a * 'b does not match the type Collections.Generic.KeyValuePair<string, int>". It may also be possible add type annotations rather than Map.toSeq.
I'm currently generating a sequence in a similar way to:
migrators
|> Seq.map (fun m -> m())
The migrator function is ultimately returning a discriminated union like:
type MigratorResult =
| Success of string * TimeSpan
| Error of string * Exception
I want to stop the map once I encounter my first Error but I need to include the Error in the final sequence.
I have something like the following to display a final message to the user
match results |> List.rev with
| [] -> "No results equals no migrators"
| head :: _ ->
match head with
| Success (dt, t) -> "All migrators succeeded"
| Error (dt, ex) -> "Migration halted owing to error"
So I need:
A way to stop the mapping when one of the map steps produces an Error
A way to have that error be the final element added to the sequence
I appreciate there may be a different sequence method other than map that will do this, I'm new to F# and searching online hasn't yielded anything as yet!
I guess there are multiple approaches here, but one way would be to use unfold:
migrators
|> Seq.unfold (fun ms ->
match ms with
| m :: tl ->
match m () with
| Success res -> Some (Success res, tl)
| Error res -> Some (Error res, [])
| [] -> None)
|> List.ofSeq
Note the List.ofSeq at the end, that's just there for realizing the sequence. A different way to go would be to use sequence comprehensions, some might say it results in a clearer code.
The ugly things Tomaš alludes to are 1) mutable state, and 2) manipulation of the underlying enumerator. A higher-order function which returns up to and including when the predicate holds would then look like this:
module Seq =
let takeUntil pred (xs : _ seq) = seq{
use en = xs.GetEnumerator()
let flag = ref true
while !flag && en.MoveNext() do
flag := not <| pred en.Current
yield en.Current }
seq{1..10} |> Seq.takeUntil (fun x -> x % 5 = 0)
|> Seq.toList
// val it : int list = [1; 2; 3; 4; 5]
For your specific application, you'd map the cases of the DU to a boolean.
(migrators : seq<MigratorResult>)
|> Seq.takeUntil (function Success _ -> false | Error _ -> true)
I think the answer from #scrwtp is probably the nicest way to do this if your input is reasonably small (and you can turn it into an F# list to use pattern matching). I'll add one more version, which works when your input is just a sequence and you do not want to turn it into a list.
Essentially, you want to do something that's almost like Seq.takeWhile, but it gives you one additional item at the end (the one, for which the predicate fails).
To use a simpler example, the following returns all numbers from a sequence until one that is divisible by 5:
let nums = [ 2 .. 10 ]
nums
|> Seq.map (fun m -> m % 5)
|> Seq.takeWhile (fun n -> n <> 0)
So, you basically just need to look one element ahead - to do this, you could use Seq.pairwise which gives you the current and the next element in the sequence"
nums
|> Seq.map (fun m -> m % 5)
|> Seq.pairwise // Get sequence of pairs with the next value
|> Seq.takeWhile (fun (p, n) -> p <> 0) // Look at the next value for test
|> Seq.mapi (fun i (p, n) -> // For the first item, we return both
if i = 0 then [p;n] else [n]) // for all other, we return the second
|> Seq.concat
The only ugly thing here is that you then need to flatten the sequence again using mapi and concat.
This is not very nice, so a good thing to do would be to define your own higher-order function like Seq.takeUntilAfter that encapsulates the behavior you need (and hides all the ugly things). Then your code could just use the function and look nice & readable (and you can experiment with other ways of implementing this).
I have a an F# list of classes for which I am using properties to access data (i'm using a library developed in C#). I would like to group by one property then apply a separate function to each property in the second item of the resulting tuple.
Example:
let grouped = list |> Seq.groupBy (fun x -> x.Year) //group by the year property. Results in Seq<int * seq<myClass>>
|> Seq.map (fun (a, b) -> (a, //How to map generic functions to each remaining property in the second tuple?
Hopefully this will make sense to someone. My second tuple item is a seq resulting from the groupBy. Each remaining property in MyClass needs to have a different function applying to it. In the past to sum a property i have just done something like:
|> Seq.map (fun (a, b) -> (a, b |> Seq.SumBy (fun x -> x.myProperty)))
I'd like to do something like this using Seq.map for several properties.
Many Thanks for any help at all,
Richard
You need to somehow specify the properties that you want to work with - the simplest way is to create a list of functions that read the properties. Assuming your type is MyType, you can write something like this:
let properties = [ (fun (x:MyType) -> x.MyProperty) ]
After you construct groups, you can then iterate over all properties in properties (using List.map or F# list comprehension) and caculate values |> Seq.sumBy prop where values is the group and prop is the current property:
let grouped =
list
|> Seq.groupBy (fun x -> x.Year)
|> Seq.map (fun (key, values) ->
(key, [for prop in properties -> values |> Seq.sumBy prop ])
If you need to use other aggregation functions than Seq.sumBy, then you can build a list of aggregating operations that you need to run (instead of a list of properties).
let properties = [ "MyPropSum", Seq.sumBy (fun (x:MyType) -> x.MyProperty);
"MyProp2Avg", Seq.averageBy (fun (x:MyType) -> x.MyProperty2) ]
To make further processing easier, I would probably build a dictionary with the results - this can be easily done by passing the list with name-value pairs to the dict function:
let grouped =
list
|> Seq.groupBy (fun x -> x.Year)
|> Seq.map (fun (key, values) ->
(key, dict [for name, aggregate in properties -> name, aggregate values ])