RamdaJS 转换对象并使用另一个列表进行查找

RamdaJS transform object and do lookup with another lists

继续
let children = [
  { "name": "Bob", "age": 8, "father": "Mike" },
  { "name": "David", "age": 10, "father": "Mike" },
  { "name": "Amy", "age": 2, "father": "Mike" },
  { "name": "Jeff", "age": 11, "father": "Jack" }
]

let schoolList = [
  { "name": "Bob", "class": "8-A", "school": "School 1" },
  { "name": "David", "class": "10-B", "school": "School 1" },
  { "name": "Amy", "class": "2-A", "school": "School 1" },
  { "name": "Jeff", "class": "11-C", "school": "School 1" }
]

到目前为止我做了什么。

R.pipe(
  R.groupBy(R.prop('father')),
  R.map(R.applySpec({
    father: R.pipe(R.head, R.prop('father')),
    count: R.length,
    kids: R.map(R.dissoc('father')),
    class: R.map(R.prop('class'))R.find(R.propEq('name',R.pipe(R.head, R.prop('name'))), schoolList)
  })),
  R.values()
)(children)

预期输出是 class 属性 附加到嵌套的 kids 数组。

{
    "father": "Jack",
    "count" : 1,
    "kids": [
      { "name": "Jeff", "age": 11, "class" : "11-C" }
    ]
  }

使用 R.indexByschoolList 转换为 object 的字典。通过使用翻转道具从查找中获取来创建 pickFromLookupByName。使用pick提取你想要的道具

要将 class 添加到孩子 object 使用 R.converge 将孩子 object 与 R.identity 相加,并使用 pickClass获得包含 class 的 object,并将两者与 R.mergeRight.

合并

const { pipe, groupBy, prop, applySpec, head, length, map, dissoc, values, indexBy, converge, mergeRight, flip, pick, identity } = R

const schoolList = [{"name":"Bob","class":"8-A","school":"School 1"},{"name":"David","class":"10-B","school":"School 1"},{"name":"Amy","class":"2-A","school":"School 1"},{"name":"Jeff","class":"11-C","school":"School 1"}]

const schoolLookup = indexBy(prop('name'), schoolList);

const pickFromLookupByName = (propList) => pipe(
  flip(prop)(schoolLookup),
  pick(propList),
)

const pickClass = pickFromLookupByName(['class']) // convenience method to get an object containing the class

const fn = pipe(
  groupBy(prop('father')),
  map(applySpec({
    father: pipe(head, prop('father')),
    count: length,
    kids: map(pipe(
      dissoc('father'),
      converge(mergeRight, [identity, pipe(prop('name'), pickClass)])
    ))
  })),
  values
)

const children = [{"name":"Bob","age":8,"father":"Mike"},{"name":"David","age":10,"father":"Mike"},{"name":"Amy","age":2,"father":"Mike"},{"name":"Jeff","age":11,"father":"Jack"}]

const result = fn(children)

console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.26.1/ramda.js"></script>

如果实际的schoolList很长,我会使用OriDrori的答案。但如果它相当短,那么这可能会更干净一些,即使效率较低:

const expandChild = schoolList => child => ({
  ...child,
  class: defaultTo(
    {class: 'unknown'}, 
    find(propEq('name', child.name), schoolList)
  ).class
})

const groupChildren = schoolList => pipe(
  groupBy(prop('father')),
  map(applySpec({
    father: pipe(head, prop('father')),
    count: length,
    kids: map(pipe(dissoc('father'), expandChild(schoolList)))
  })),
  values,
)

let children = [{ name: "Bob", age: 8, father: "Mike" }, { name: "David", age: 10, father: "Mike" }, { name: "Amy", age: 2, father: "Mike" }, { name: "Jeff", age: 11, father: "Jack" }, { name: "Sue", age: 9, father: "Jack" }]

let schoolList = [{ name: "Bob", class: "8-A", school: "School 1" }, { name: "David", class: "10-B", school: "School 1" }, { name: "Amy", class: "2-A", school: "School 1" }, { name: "Jeff", class: "11-C", school: "School 1" }]

console.log (groupChildren (schoolList) (children))
<script src="https://bundle.run/ramda@0.26.1"></script><script>
const {defaultTo, find, propEq, pipe, groupBy, map, applySpec, head, prop, length, dissoc, values} = ramda
</script>

注意 school 的默认值,以防 child 的名字不在 schoolList 中。