F#函数在Excel-Dna中对Excel“变体”进行排序

时间:2019-05-30 12:56:10

标签: sorting f# excel-dna

当尝试对一维变量数组进行排序时(这里的“变量”是指所有Excel类型,例如bool,double(和日期),字符串,各种错误...),具有以下功能:

[<ExcelFunction(Category="test", Description="sort variants.")>]
    let sort_variant ([<ExcelArgument(Description= "Array to sort.")>] arr : obj[]): obj[] =
        arr
        |> Array.sort

我得到以下错误:Error FS0001 The type 'obj' does not support the 'comparison' constraint. For example, it does not support the 'System.IComparable' interface,可能意味着所有obj类型都没有通用排序功能。

但是Excel具有自然的排序功能,我想模仿该功能(至少可以理解)。例如,双精度(和日期)<字符串

我的问题:在F#/ Excel-Dna中对“变量”数组进行排序的惯用方式是什么? (我在接受obj[]并返回obj[]的函数之后,没有别的,不是宏...)

我的(临时的)解决方案: 我创建了一个“歧视的工会”类型

type XLVariant = D of double | S of string | B of bool | NIL of string

(不确定NIL是否必要,但并没有伤害。同样,在我的实际代码中,我添加了一个DT of DateTime实例,因为我需要区分双精度数和日期)。

let toXLVariant (x : obj) : XLVariant =
    match x with
    | :? double as d -> D d
    | :? string as s -> S s
    | :? bool   as b -> B b
    | _              -> NIL "unknown match"

let ofXLVariant (x : XLVariant) : obj =
    match x with
    | D d   -> box d
    | S s   -> box s
    | B b   -> box b
    | NIL _ -> box ExcelError.ExcelErrorRef

[<ExcelFunction(Category="test", Description="sort variants.")>]
let sort_variant ([<ExcelArgument(Description= "Array to sort.")>] arr : obj[]): obj[] =
    arr
    |> Array.map toXLVariant
    |> Array.sort
    |> Array.map ofXLVariant

(为简单起见,我错过了Errors类型,但是想法是相同的)

1 个答案:

答案 0 :(得分:1)

对我来说,这似乎更明确了,因为它只是坚持使用CLR类型系统:

// Compare objects in the way Excel would
let xlCompare (v1 : obj) (v2 : obj) =
    match (v1, v2) with
    | (:? double as d1), (:? double as d2) -> d1.CompareTo(d2)
    | (:? double), _ -> -1
    | _, (:? double) -> 1
    | (:? string as s1), (:? string as s2) -> s1.CompareTo(s2)
    | (:? string), _ -> -1
    | _, (:? string) -> 1
    | (:? bool as b1), (:? bool as b2) -> b1.CompareTo(b2)
    | (:? bool), _ -> -1
    | _, (:? bool) -> 1
    | _              -> 2

[<ExcelFunction(Category="test", Description="sort variants.")>]
let sort_variant ([<ExcelArgument(Description= "Array to sort.")>] arr : obj[]): obj[] =
    Array.sortWith xlCompare arr