使用ramda将包含数组的对象解压缩到对象数组中

Unzip object which contain array into array of object using ramda

我是函数式编程(和 ramda)的菜鸟。 我不知道该怎么做:

[{  
      "name":"SBRF IANUA EFS CC Integration",
      "expand":false,
      "check":"N",
      "jsonDiffPath":"/repo/Dynamics/Business Service/SBRF IANUA EFS CC Integration",
      "changeCount":1,
      "items":[  
         {  
            "name":"CRP-37920",
            "expand":false,
            "check":"N",
            "jsonDiffPath":null,
            "changeCount":1,
            "items":[],
            "op":"MODIFY",
            "oldSnapshot":"723012",
            "newSnapshot":"948053",
            "myChange":false
         }
      ],
"id":"F5ZGK4DPF5CHS3TBNVUWG4ZPIJ2XG2LOMVZXGICTMVZHM2LDMUXVGQSSIYQESQKOKVASARKGKMQEGQZAJFXHIZLHOJQXI2LPNY======",
      "objectId":"30263",
      "group":"repo",
      "category":"Dynamics",
      "type":"Business Service"
   }
]

像这样:

[  
   {  
      "name":"[CRP-37920] SBRF IANUA EFS CC Integration",
      "expand":false,
      "check":"N",
      "jsonDiffPath":"/repo/Dynamics/Business Service/SBRF IANUA EFS CC Integration",
      "changeCount":1,
      "op":"MODIFY",
      "oldSnapshot":"723012",
      "newSnapshot":"948053",
      "items":[],
  "id":"F5ZGK4DPF5CHS3TBNVUWG4ZPIJ2XG2LOMVZXGICTMVZHM2LDMUXVGQSSIYQESQKOKVASARKGKMQEGQZAJFXHIZLHOJQXI2LPNY======",
      "objectId":"30263",
      "group":"repo",
      "category":"Dynamics",
      "type":"Business Service"
   }
]

"items" 数组的每个元素都应与其父级合并(具有内部数组的对象 => 进入对象数组)

提前致谢)

// array of parents
const p = [
  {
    name: 'SBRF IANUA EFS CC Integration',
    expand: false,
    check: 'N',
    jsonDiffPath: '/repo/Dynamics/Business Service/SBRF IANUA EFS CC Integration',
    changeCount: 1,
    items: [
      {
        name: 'CRP-37920',
        expand: false,
        check: 'N',
        jsonDiffPath: null,
        changeCount: 1,
        items: [],
        op: 'MODIFY',
        oldSnapshot: '723012',
        newSnapshot: '948053',
        myChange: false
      }
    ],
    id: 'F5ZGK4DPF5CHS3TBNVUWG4ZPIJ2XG2LOMVZXGICTMVZHM2LDMUXVGQSSIYQESQKOKVASARKGKMQEGQZAJFXHIZLHOJQXI2LPNY======',
    objectId: '30263',
    group: 'repo',
    category: 'Dynamics',
    type: 'Business Service'
  }
];

// define a function that describes how a child should merge with its parent
function merge(p) {
  // p is the parent object
  // c are all of p's children defined in items
  const child = p['items'];
  // on the item that we return we only want keys that appear in the parent
  // create an array for the flattened results
  const f = [];
  child.forEach(el => {
    let keys = Object.keys(p);
    // clone the parent object
    let c = Object.assign({}, p);
    // basically unset the items since we are already iterating of them
    child['items'] = [];
    // now iterate over all of the childrens attrs described by the parents parameters
    keys.forEach(k => {
      // the childs value for each key
      const val = el[k];
      if (val !== undefined && val !== null) {
        // handle your special cases in here, such as the name
        if (k === 'name') {
          c['name'] = '[' + el['name'] + '] ' + c['name'];
        } else {
          // default behavior for the non specific cases
          c[k] = el[k]
        }
      }
    });
    // add the object to the array of flattened children
    f.push(c);
  });
  return f;
}

// iterate over all of the parents and their children
// to do this we want to apply a map to all of the parents
const m = p.map(el => merge(el));

JS Bin of the example merge function.

据我所知,你没有充分的理由为此使用 lodash (_) 或 ramda 之类的东西,因为它不是直接的 flatten/merge。您想要根据密钥执行特定的操作,因此您将不得不推出一个自定义函数来处理它。

我提供的代码有大量文档并且相对简单,但为了学习起见,这里是一个高级概述:

  • 你有一个 object 数组,其中每个 object 是一个 parent 到 N children.
  • 我们想将每个 child 与其 parent
  • 合并
  • 根据示例输出,我们只想包含存在于 parent object 中的 object 属性,并且 child 属性值将仅在 parent 值不为 null 或未定义时覆盖
  • 需要自定义覆盖行为,具体取决于要合并的属性

一种可能性,如果我正确理解您的要求,可能是这样的:

const alterOne = chain(
  children => parent => map(merge(__, dissoc('items', parent)), children),
  prop('items')
)

const alterAll = pipe(map(alterOne), flatten)

可能有一些好方法可以使 alterOne 中传递给 chain 的第一个函数不带任何点,但这对我来说已经很可读了。

您可以在 Ramda REPL.

中看到这个

我是 Ramda 的新手,但我想试试看。我的解决方案确实包括您示例中的自定义名称合并规则。

let concatName = (key, parent, children) => key === 'name' ? `[${children}] ${parent}` : children;

const mergeItems = R.map((item ) => {
    return R.mergeWithKey(concatName, item, R.mergeAll(R.prop('items',item)))}
)

由于不清楚 "deep" 嵌套项可能是怎样的,也不清楚在那种情况下合并规则应该是什么,所以我没有让它更深入。