Функция F # для сортировки Excel "вариантов" в Excel-ДНК - PullRequest
3 голосов
/ 30 мая 2019

При попытке сортировать массив вариантов 1d (здесь под «вариантом» я имею в виду все типы Excel, например, bool, double (и date), string, различные ошибки ...) с помощью следующей функции:

[<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 есть естественная функция упорядочения, которую я хотел бы эмулировать (по крайней мере, приблизительный). Например, двойной (и даты) <строка <bool <ошибка ... </p>

Мой вопрос : Какой идиоматический способ сортировки массива «вариантов» в 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

(ради простоты я пропустил типы ошибок, но идея та же)

1 Ответ

2 голосов
/ 01 июня 2019

Это кажется мне более понятным, поскольку оно просто придерживается системы типов 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
...