繁体   English   中英

在使用Ramda挑选另一个键之后,如何追加到数组

[英]How to append to an array after cherry picking keys of another using Ramda

我有一个现有的对象数组

const oldData = [
  {'one': 1, 'two': 2},
  {'one': 3, 'two': 4}
];

我有一个新的对象数组:

const newData = [
  {'three': 5, 'two': 6, 'one': 7},
  {'five': 8, 'one': 9, 'two': 10}, 
];

我有一个包含要提取的对象道具的数组(这是一个变量)

const columnMeta = ['one', 'two'];

我想使用Ramda创建可组合,可重用的函数。 此函数应仅提取newArray的所选columnMeta属性,并将其附加到oldArray中存在的内容中

以下工作正常,但似乎有点冗长(且几乎不可重用..)

// simple enough, join two arrays using the spread operator
const appendData = curry((curr, prev) => [...prev, ...curr]);

// get a subset of an object, given an array of keys
const extractByColumnMeta = curry((k, obj) => zipObj(k, props(k)(obj)));

// create a composable function that takes an array of keys
const mapDataByColumns = compose(map, extractByColumnMeta)(columnMeta);

// compose a new function that would take a the newData & oldData
const mergeDataAfterMap = compose(appendData, mapDataByColumns);

// works, but I'm sure I can do better :)
mergeDataAfterMap(newData)(oldData);

// => [{one: 1, two: 2}, {one: 3, two: 4}, {one: 7, two: 6}, {one: 9, two: 10}]

非拉姆达方式,见小提琴

const mapDataToColumns = (fields, oldData, newData) => {
    // a new array. anything in oldData is included
    return [...oldData, ...newData.map(row => {
        // reduce to return only wanted keys
        return fields.reduce((acc, field) => {
          // add to accumulator or return
          return row.hasOwnProperty(field) 
            ? {...acc, [field]:row[field]}
            : acc;
        }, {});
    })];
}

怎么样:

const mergeSelectAttr = R.curry((oldData, columnMeta, newData) => 
  R.compose(
    R.concat(oldData), 
    R.map(R.pick(columnMeta))
  )(newData) 
)

兰达小提琴

我想说这会产生比当前答案更灵活的api,您可以根据需要方便地调用它:

  • mergeSelectAttr(oldData, columnMeta, newData)
  • mergeSelectAttr(oldData)(columnMeta, newData)
  • mergeSelectAttr(oldData, columnMeta)(newData)

即使在稍后的阶段获得newData ,使用此解决方案获得的一个主要优点仍然可以发挥作用,例如从api调用/数据库结果中newData ,由于newData ,它仍然可以很好地工作。 当然,您还可以根据首先获取的内容来更改oldDatacolumnMeta的顺序

例如:

// You have olData and coulmnMeta now, but not newData:
const merger = mergeSelectAttr(oldData, columnMeta)
    .
    .
    .
    .
// A little while later, when you have access to newData:

const finalValue = merger(newData)

您只需要用R.pick来组成R.pick ,但是R.concat些技巧。 您正在尝试将一元函数R.pick(columnMenta)与二进制函数R.concat

const compose2 = R.compose(R.compose, R.compose)

const foo = compose2(R.map(R.pick(['one', 'two'])), R.concat)

console.log(foo(oldData, newData))
// => [{"one":1,"two":2},{"one":3,"two":4},{"one":7,"two":6}, {"one":9,"two":10}]

两个输入的任意限制使这有点虚弱,并且大多数人不喜欢compose2骗术。 如果您有多个输入数据列表,并且想要以一种明智的方式将它们合并,该怎么办? 输入R.chain

const foo = R.chain(R.map(R.pick(['one', 'two'])))

console.log(foo([oldData, newData, oldData]))
// => [{"one":1,"two":2},{"one":3,"two":4},{"one":7,"two":6},{"one":9,"two":10},{"one":1,"two":2},{"one":3,"two":4}]

注意foo现在需要一个输入数组 ,该数组可以有效地允许您根据需要组合任意数量的数据集


好的,看来您也希望columnMeta是函数的输入。 如果我们采用后一个答案,那将是最简单的

const foo = R.curry((columns, xxs) =>
  R.chain(R.map(R.pick(columns)), xxs))

console.log(foo(['one'], [oldData, newData, oldData]))
// => [{"one":1},{"one":3},{"one":7},{"one":9},{"one":1},{"one":3}]

console.log(foo(['two'], [oldData, newData, oldData]))
// => [{"two":2},{"two":4},{"two":6},{"two":10},{"two":2},{"two":4}]

console.log(foo(['one', 'two'], [oldData, newData, oldData]))
// => [{"one":1,"two":2},{"one":3,"two":4},{"one":7,"two":6},{"one":9,"two":10},{"one":1,"two":2},{"one":3,"two":4}]

如果您不介意此API:

mergeAndPick(columnMeta, [oldData, newData]);
//=> [{"one": 1, "two": 2}, {"one": 3, "two": 4}, 
//    {"one": 7, "two": 6}, {"one": 9, "two": 10}]

然后,您可以像这样简单地编写它:

const mergeAndPick = R.useWith(R.project, [R.identity, R.unnest]);

如果您真的想要这样:

mergeDataAfterMap(columnMeta, oldData, newData);
//=> [{"one": 1, "two": 2}, {"one": 3, "two": 4}, 
//    {"one": 7, "two": 6}, {"one": 9, "two": 10}]

然后,您可以在上面之上构建它。

const mergeDataAfterMap = (columnMeta, oldData, newData) => 
    mergeAndPick(columnMeta, [oldData, newData]);

但是第一个更灵活,允许您指定任意数量的列表进行组合。

它建立在一个非常不常见的useWith函数useWith ,该函数使以无分方式组合功能变得更加容易。 在ES6时代,它的优势并不明显,可以重写为

const mergeAndPick = R.curry((columnMeta, lists) => 
    R.project(columnMeta, R.unnest(lists)));

您可以在Ramda REPL上看到所有这些操作。

在@ScottSauyet的答案和对@naomik答案的评论的基础上,我想到了这一点:

const pickAndMerge = compose(chain, project);

然后就是

pickAndMerge(columnMeta)([oldData, newData]);
//=> [{"one": 1, "two": 2}, {"one": 3, "two": 4}, 
//    {"one": 7, "two": 6}, {"one": 9, "two": 10}]

您可以在Ramda REPL中看到它

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM