使用 ramda 转换集合

Transforming collection using ramda

我想使用 ramba 进行以下转换

输入集合

const vals = [
        {metric: "Sales", measure:100, period_end_date: "2021-12-31", period_type: 'Annual' },
        {metric: "EBT", measure:101,  period_end_date: "2021-12-31", period_type: 'Annual' },
        {metric: "Sales", measure:100, period_end_date: "2021-09-30", period_type: 'Qtr' },
        {metric: "EBT", measure:101,  period_end_date: "2021-09-30", period_type: 'Qtr' }
       ]

输出

 {  
   "2021-09-30|Qtr": [{"Sales": 100}, {"EBT": 101],  
   "2021-12-31|Annual": [{"Sales": 100, }, {"EBT": 101,}] 
 }

我能够非常接近这个

const keyGen = compose(objOf('key'), join('|'),  props(['period_end_date','period_type']))// + '|' + prop("period_type",o) }

const valGen = compose(apply(objOf), R.ap([R.prop('metric'), R.prop('measure')]), of )

const f4 = map(compose(apply(merge), R.ap([keyGen, valGen]), of))

const result =compose(groupBy(prop('key')),f4 ) (vals)

这给了我以下结果

{"2021-09-30|Qtr": [{"Sales": 100, "key": "2021-09-30|Qtr"}, 
                    {"EBT": 101, "key": "2021-09-30|Qtr"}], 
 "2021-12-31|Annual": [{"Sales": 100, "key": "2021-12-31|Annual"}, 
                       {"EBT": 101, "key": "2021-12-31|Annual"}]}

现在我需要从内部集合中删除 key。我想知道有没有更好的选择。

也许您应该简化您的代码并只使用一个简单的函数来将您的集合减少到所需的输出?我使用了 Array.prototype.reduce,它很容易翻译成 Ramda 的函数式、无点、柯里化风格:

const convert = (acc, item) => {
  const name = `${item.period_end_date}|${item.period_type}`
  if (!acc[name]) acc[name] = []
  acc[name].push({ [item.metric]: item.measure })
  return acc
}

const transform = R.reduce(convert, {})
transform(vals)

没有 Ramda 的工作片段:

const vals = [{
    metric: "Sales",
    measure: 100,
    period_end_date: "2021-12-31",
    period_type: 'Annual'
  },
  {
    metric: "EBT",
    measure: 101,
    period_end_date: "2021-12-31",
    period_type: 'Annual'
  },
  {
    metric: "Sales",
    measure: 100,
    period_end_date: "2021-09-30",
    period_type: 'Qtr'
  },
  {
    metric: "EBT",
    measure: 101,
    period_end_date: "2021-09-30",
    period_type: 'Qtr'
  }
]

const result = vals.reduce((acc, item) => {
  const name = `${item.period_end_date}|${item.period_type}`
  if (!acc[name]) acc[name] = []
  acc[name].push({
    [item.metric]: item.measure
  })
  return acc
}, {})

console.log(result)

R.reduceBy 可用于对列表中的项目进行分组,然后减少具有相同键的每组项目。

const vals = [
  {metric: "Sales", measure:100, period_end_date: "2021-12-31", period_type: 'Annual' },
  {metric: "EBT", measure:101,  period_end_date: "2021-12-31", period_type: 'Annual' },
  {metric: "Sales", measure:100, period_end_date: "2021-09-30", period_type: 'Qtr' },
  {metric: "EBT", measure:101,  period_end_date: "2021-09-30", period_type: 'Qtr' }
]

const fn = R.reduceBy(
  (list, {metric, measure}) => R.append({[metric]: measure}, list),
  [],
  ({period_end_date, period_type}) => `${period_end_date}|${period_type}`,
)

console.log(fn(vals))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

另一种可能是这样的:

const vals = [
  {metric: "Sales", measure:100, period_end_date: "2021-12-31", period_type: 'Annual' },
  {metric: "EBT", measure:101,  period_end_date: "2021-12-31", period_type: 'Annual' },
  {metric: "Sales", measure:100, period_end_date: "2021-09-30", period_type: 'Qtr' },
  {metric: "EBT", measure:101,  period_end_date: "2021-09-30", period_type: 'Qtr' }
]

const fn = R.pipe(
  R.groupBy(({period_end_date, period_type}) => `${period_end_date}|${period_type}`),
  R.map(R.map(R.lift(R.objOf)(R.prop('metric'), R.prop('measure'))))
);

console.log(fn(vals))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

这里的关键点是liftobjOf,这样它就不会处理,而是处理值的容器,在这种情况下,函数 return 它们(prop('metric')prop('measure')。)