如何创建一个构建器函数来转换键值数据,并提供数据和输出的 structure/format

How to create a builder function that transforms key-value data, and is supplied with both the data and the structure/format of the output

这是以下问题的后续问题:

给定键值格式的数据,我想将其转换为新的结构。

// given data example #1
const dataAnimals = {"monkeys": 10, "alligators": 20}

// given data example #2
const dataColors = {"red": 100, "green": 4, "yellow": 17}

并且 output 的新结构可以从任何预先指定的格式中选择。 如果我们坚持使用 dataAnimals 作为输入,则有三种可能的输出格式:

结构类型1

[
    {
        label: {
            en: "monkeys"
        },
        value: 10
    },
    {
        label: {
            en: "alligators"
        },
        value: 20
    }
]

结构类型2

[
    {
        count: 10,
        label: {
            en: "monkeys"
        }
    },
    {
        count: 20,
        label: {
            en: "alligators"
        }
    }
]

结构类型3

[
    {
        count: 10,
        value: "monkeys"
    },
    {
        count: 20,
        value: "alligators"
    }
]

我可能会有更多类型的结构。


我想知道是否有办法 提供 chosen/desired 结构(即将结构与输入数据本身一起传递给构建器函数)。

到目前为止,使用 ramda 我只能编写 3 个单独的构建器函数,每个函数中的结构都被硬编码:

const buildArr1 = R.pipe(R.toPairs, R.map(R.applySpec({value: R.nth(1), label: {en: R.nth(0)}})))
const buildArr2 = R.pipe(R.toPairs, R.map(R.applySpec({count: R.nth(1), label: {en: R.nth(0)}})))
const buildArr3 = R.pipe(R.toPairs, R.map(R.applySpec({value: R.nth(0), count: R.nth(1)})))

buildArr1(dataAnimals)
buildArr2(dataAnimals)
buildArr3(dataAnimals)

buildArr1()buildArr2()buildArr3() 之间的区别很微妙,仅在 applySpec() 内部的结构方面。所以这让我开始思考,是否有可能只有 one 函数 buildArr(),它将要转换的数据和要返回的格式。

// pseudo-code for desired code
buildArr(dataAnimals, structureType1)
// which will return
// [
//     {
//         label: {
//             en: "monkeys"
//         },
//         value: 10
//     },
//     {
//         label: {
//             en: "alligators"
//         },
//         value: 20
//     }
// ]


buildArr(dataAnimals, structureType2)

// [
//     {
//         count: 10,
//         label: {
//             en: "monkeys"
//         }
//     },
//     {
//         count: 20,
//         label: {
//             en: "alligators"
//         }
//     }
// ]

有什么正确的方法可以做这样的事情吗?我也不确定 structureType1/structureType2 被传递的性质应该是什么。一个东西?或者更确切地说是一个“知道与输入数据交互”的函数?

请注意,虽然这个问题围绕 ramda,但(对我而言)它似乎比特定的库更广泛。


编辑


用户 可以使用纯 JS 实现编写单个构建器(即 buildArr1()buildArr2 等)。这说明了我上面的观点,这不一定是一个 ramda 问题。

const buildArr1PlainJS = (o) => ({data: Object .entries (o) .map (([k, v]) => ({value: v, label: {en: k}}))})
const buildArr2PlainJS = (o) => ({data: Object .entries (o) .map (([k, v]) => ({count: v, label: {en: k}}))})
const buildArr3PlainJS = (o) => ({data: Object .entries (o) .map (([k, v]) => ({value: k, count: v}))})

我认为您可以通过将格式化函数传递给通用处理器来相当轻松地完成此操作。它可能看起来像这样:

// main function
const transform = (fn) => (o) => Object .entries (o) .map (([k, v]) => fn (k, v))

// formatting functions
const format1 = transform ((k, v) => ({label: {en: k}, value: v}))
const format2 = transform ((k, v) => ({count: v, label: {en: k}}))
const format3 = transform ((k, v) => ({count: v, value: k}))

// input data
const inputs = {
  dataAnimals: {"monkeys": 10, "alligators": 20},
  dataColors: {"red": 100, "green": 4, "yellow": 17},
};

// demo
Object .entries (inputs) .forEach (([name, input]) => [format1, format2, format3] .forEach ((format, i) =>
  console .log (`${name}, format ${i + 1}:`, format (input))
))
.as-console-wrapper {max-height: 100% !important; top: 0}

同样,我没有看到 Ramda 在这里增加太多价值,尽管我们当然可以使用 Ramda 的工具来做到这一点。我们可能会写:

const transform = (fn) => (o) => map (unapply (fn)) (toPairs (o))

或者,如果您有 point-free 恋物癖,即使这样:

const transform = compose (flip (o) (toPairs), map, unapply)

但我不认为这些——尤其是后者——增加了任何有用的东西。