2
\$\begingroup\$

The below code takes an incoming sequence of objects, checks each object's type and then yields the object in a specific order. This is all taking place in an active pattern. As I am still new to F#, I would like to know if there is a better or more efficient way of accomplishing this task.

    type ArticleObj = 
    | Submission
    | Photos
    | ReviewRating
    | BusinessReviewRating
    | ArticleTag


let (|OrderArticleObj|_|) (objSeq : seq<obj>) =

    // Create DU array
    let articleParts = [| 
                        Submission; Photos; ReviewRating; 
                        BusinessReviewRating; ArticleTag 
                    |]

    // create ordered array of objects
    let orderedSeq = seq{
                for row in articleParts do
                    for row2 in objSeq do
                        match row with
                        | Submission -> 
                                        let isValid =
                                            match row2 with
                                            | :? ArticleSubmission as Sub -> true
                                            | _ -> false

                                        if isValid
                                        then
                                            yield row2
                        | Photos ->
                                    let isValid =
                                            match row2 with
                                            | :? seq<Photos> as Photo -> true
                                            | _ -> false

                                    if isValid
                                    then
                                        yield row2
                        | ReviewRating ->
                                            let isValid =
                                                match row2 with
                                                | :? ArticleReviewRating as RevRating -> true
                                                | _ -> false

                                            if isValid
                                            then
                                                yield row2
                        | BusinessReviewRating ->
                                                    let isValid =
                                                        match row2 with
                                                        | :? BusinessReviewRating as BizRev -> true
                                                        | _ -> false

                                                    if isValid
                                                    then
                                                        yield row2
                        | ArticleTag ->
                                        let isValid =
                                            match row2 with
                                            | :? seq<ArticleTags> as ArtTag -> true
                                            | _ -> false

                                        if isValid
                                        then
                                            yield row2
            }

    if not (Seq.isEmpty orderedSeq)
    then Some(orderedSeq) else None
\$\endgroup\$
  • \$\begingroup\$ you could indent much less - I would probably have Submission; Photos; ReviewRating; only indented 8 spaces for example \$\endgroup\$ – John Palmer Dec 3 '14 at 22:29
3
\$\begingroup\$

You could define a sorted list of the types and use that to sort the input. Here's what a function that does that would look like.

let sortArticles : seq<obj> -> seq<obj> =
    let sorted =
        [
            typeof<ArticleSubmission>
            typeof<seq<Photos>>
            typeof<ArticleReviewRating>
            typeof<BusinessReviewRating>
            typeof<seq<ArticleTags>>
        ]
    Seq.sortBy (fun o -> sorted |> List.findIndex ((=) (o.GetType())))
\$\endgroup\$
  • \$\begingroup\$ I understand the gist of what's going on, but can you explain the purpose of the (=) operator in this context? I haven't seen it used this way before. \$\endgroup\$ – user1206480 Dec 4 '14 at 1:32
  • \$\begingroup\$ Also, are there any errors to handle if a type is not matched? \$\endgroup\$ – user1206480 Dec 4 '14 at 1:56
  • \$\begingroup\$ (=) (o.GetType()) is partially applying the = operator. It's shorthand for fun ty -> ty = o.GetType(). List.findIndex throws an ArgumentException if a matching item is not found. \$\endgroup\$ – Daniel Dec 4 '14 at 15:07
  • \$\begingroup\$ I am now confused the longer I look at this. Doesn't the above inner function return an int as a key for the sortBy function? How would that help me sort a seq<obj> given to the sortBy function? \$\endgroup\$ – user1206480 Dec 4 '14 at 15:10
  • 1
    \$\begingroup\$ Right. You can think of the lambda as a "mapping" from input element to key. Or, as the docs explain: Applies a key-generating function to each element of a sequence and yields a sequence ordered by keys \$\endgroup\$ – Daniel Dec 4 '14 at 17:31

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.