Reputation: 11439
In C# you would just use SelectMany
which has an overload for holding onto the parent object. How do you do the same thing in F#? That is, I want to iterate over a set of assemblies and return all of those assemblies that have classes implementing a specific attribute.
I know I collect
is similar to select many, but I'm not sure how to use it while maintaining the parent (assembly) information.
Upvotes: 0
Views: 334
Reputation: 243106
You can implement SelectMany
using collect
by applying a map
to the collection of "children" that you want to return for each element of the "parent" collection:
Assuming you have some source
and want to get children using getChildren
(for each element in source
) and then you want to calculate the result using selectResult
that takes both child and parent, you can write the following using SelectMany
:
source.SelectMany
( (fun parent -> getChildren parent),
(fun parent child -> selectResult parent child ) )
Using collect
, the same code looks as follows (note that the map
operation is applied inside the lambda function that we're passing to collect
- where parent
is still in scope):
source |> Seq.collect (fun parent ->
getChildren parent
|> Seq.map (fun child ->
selectResult parent child ))
It is also worth noting that the behavior captured by SelectMany
can be implemented - perhaps in a more readable way - using F# sequence expressions like this:
seq { for parent in source do
for child in getChildren parent do
yield selectResult parent child }
Upvotes: 1
Reputation: 144206
It looks like you just need filter
instead of collect
:
let hasTypeWithAttribute<'t when 't :> Attribute> (a: Assembly) = a.GetTypes() |> Array.exists (fun t -> t.GetCustomAttributes(typeof<'t>, true).Length > 0)
let assemblies = inputSet |> Set.filter hasTypeWithAttribute<AttributeName>
Upvotes: 1