简体   繁体   English

使用 Ramda 减少对象数组中的多个属性并省略其他属性

[英]Reduce multiple properties in array of array of objects and omit other properties using Ramda

I have this array of arrays with objects:我有这个带有对象的 arrays 数组:

const data = [
  [
    {
      index: 320,
      blocks: 2,
      value: '31011784785',
      participants: 1222,
      cost: '1286828506'
    },
    {
      index: 319,
      blocks: 0,
      value: '111306385',
      participants: 18,
      cost: '0'
    },
    {
      index: 318,
      blocks: 0,
      value: '14550473',
      participants: 10,
      cost: '0'
    }
  ],
  [
    {
      index: 320,
      blocks: 1,
      value: '7089001673',
      participants: 492,
      cost: '648196615'
    },
    {
      index: 319,
      blocks: 0,
      value: '13551137',
      participants: 8,
      cost: '0'
    },
    {
      index: 318,
      blocks: 0,
      value: '11499815',
      participants: 5,
      cost: '0'
    }
  ],
  [
    {
      index: 320,
      blocks: 1,
      value: '408900161',
      participants: 200,
      cost: '648196615'
    },
    {
      index: 319,
      blocks: 0,
      value: '23551231',
      participants: 10,
      cost: '0'
    },
    {
      index: 318,
      blocks: 0,
      value: '104324219',
      participants: 5,
      cost: '0'
    }
  ]
]

I would like to make a single array with objects that will have just the properties index, value, and participants where value and participants will be the sum of the 3 arrays. Eg:我想制作一个包含对象的单个数组,这些对象将仅具有属性索引、值和参与者,其中值和参与者将是 3 arrays 的总和。例如:

[
  {
      index: 320,
      value: 38509686619,
      participants: 1914,
  },
  {
      index: 319,
      value: 148408753,
      participants: 36,
  },
  {
     ...
  }
]

I would also like the value field to be a BigInt.我还希望值字段是一个 BigInt。

Inspired by this answer I made something that works but it's way too long and cumbersome.受这个答案的启发,我做了一些有用的东西,但它太长太麻烦了。

This question is different from Reduce Array of Array of Objects Using Ramda because I need two object property values and I don't know how to do this.这个问题与使用 Ramda 减少对象数组的问题不同,因为我需要两个 object 属性值,但我不知道该怎么做。

Vanila JS solution:香草 JS 解决方案:

 const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]]; const result = Object.values(data.flat().reduce((acc, { index, value, participants }) => { acc[index]??= { index, value: 0, participants: 0 }; acc[index].value += Number(value); acc[index].participants += Number(participants); return acc; }, {})); console.log(result);
 .as-console-wrapper{min-height: 100%;important: top: 0}

One Ramda approach:一种 Ramda 方法:

 const convert = pipe ( transpose, map (xs => ({ index: xs [0].index, value: xs.reduce ((a, {value}) => a + Number (value), 0), participants: sum (pluck ('participants') (xs)) })) ) const data = [[{index: 320, blocks: 2, value: "31011784785", participants: 1222, cost: "1286828506"}, {index: 319, blocks: 0, value: "111306385", participants: 18, cost: "0"}, {index: 318, blocks: 0, value: "14550473", participants: 10, cost: "0"}], [{index: 320, blocks: 1, value: "7089001673", participants: 492, cost: "648196615"}, {index: 319, blocks: 0, value: "13551137", participants: 8, cost: "0"}, {index: 318, blocks: 0, value: "11499815", participants: 5, cost: "0"}], [{index: 320, blocks: 1, value: "408900161", participants: 200, cost: "648196615"}, {index: 319, blocks: 0, value: "23551231", participants: 10, cost: "0"}, {index: 318, blocks: 0, value: "104324219", participants: 5, cost: "0"}]] console.log (convert (data))
 .as-console-wrapper {max-height: 100%;important: top: 0}
 <script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.28.0/ramda.min.js"></script> <script> const {pipe, transpose, map, sum, pluck, reduce, applySpec} = R </script>

We start with transpose , which turns this into a much easier to work with format.我们从transpose开始,它将它变成一种更容易使用的格式。 Then for each new row, we grab the index from the first record, and sum up both the participants and the values.然后对于每个新行,我们从第一条记录中获取索引,并对参与者和值求和。

Because BigInt's don't show well in the SO console, I skipped them, but the change is trivial:因为 BigInt 在 SO 控制台中显示不佳,所以我跳过了它们,但变化很小:

-    value: xs .reduce ((a, {value}) => a + Number (value), 0),
+    value: xs .reduce ((a, {value}) => a + BigInt(value), BigInt(0)),

A point-free version, if you have that fetish, is not much harder:一个无积分版本,如果你有那种迷信,也不会更难:

const convert = pipe (
  transpose,
  map (applySpec ({
    index: pipe (head, prop ('index')),
    value: reduce ((a, {value}) => a + Number (value), 0),
    // value: reduce ((a, {value}) => a + BigInt (value), BigInt (0)),
    participants: pipe (pluck ('participants'), sum)
  }))
)

After flattening, the array of arrays, you should map and pick the wanted properties and convert values to a number, and then group by, and combine each group to a single object.扁平化后,arrays 的数组,你应该 map 并选择想要的属性并将values转换为数字,然后分组,并将每个组组合成一个 object。

 const { mergeWithKey, pipe, flatten, map, pick, evolve, groupBy, prop, reduce, values } = R // merge deep and combine properties value const combine = mergeWithKey((k, l, r) => k === 'value' || k === 'participants'? l + r: r) const mergeData = pipe( flatten, // flatten to a single array map(pipe( pick(['index', 'value', 'participants']), // pick wanted properties evolve({ value: Number }) // convert values to a number )), groupBy(prop('index')), // group by the name map(reduce(combine, {})), // combine each group to a single object values, // convert back to array ) const data = [[{"index":320,"blocks":2,"value":"31011784785","participants":1222,"cost":"1286828506"},{"index":319,"blocks":0,"value":"111306385","participants":18,"cost":"0"},{"index":318,"blocks":0,"value":"14550473","participants":10,"cost":"0"}],[{"index":320,"blocks":1,"value":"7089001673","participants":492,"cost":"648196615"},{"index":319,"blocks":0,"value":"13551137","participants":8,"cost":"0"},{"index":318,"blocks":0,"value":"11499815","participants":5,"cost":"0"}],[{"index":320,"blocks":1,"value":"408900161","participants":200,"cost":"648196615"},{"index":319,"blocks":0,"value":"23551231","participants":10,"cost":"0"},{"index":318,"blocks":0,"value":"104324219","participants":5,"cost":"0"}]] const results = mergeData(data) console.log(results)
 <script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>

This solution (using JS and not rambda) attempts to use BigInt and provides the value into a prop named valueB .此解决方案(使用 JS 而不是 rambda)尝试使用 BigInt 并将值提供给名为valueB的道具。

 const groupAndSum = arr => ( Object.values( arr.flat().reduce( (acc, {index, value, participants}) => ({...acc, [index]: { index, valueB: BigInt((acc[index]?.valueB?? 0)) + BigInt(value), // valueB as big-int value: (acc[index]?.value || 0) + +value, // value as a "Number" participants: (acc[index]?.participants?? 0) + +participants } }), {} ) ).map( // to display big-int in the console within stack-snippets ({valueB, ...rest}) => ({valueB: valueB.toString(), ...rest}) ) ); const data = [ [ { index: 320, blocks: 2, value: '31011784785', participants: 1222, cost: '1286828506' }, { index: 319, blocks: 0, value: '111306385', participants: 18, cost: '0' }, { index: 318, blocks: 0, value: '14550473', participants: 10, cost: '0' } ], [ { index: 320, blocks: 1, value: '7089001673', participants: 492, cost: '648196615' }, { index: 319, blocks: 0, value: '13551137', participants: 8, cost: '0' }, { index: 318, blocks: 0, value: '11499815', participants: 5, cost: '0' } ], [ { index: 320, blocks: 1, value: '408900161', participants: 200, cost: '648196615' }, { index: 319, blocks: 0, value: '23551231', participants: 10, cost: '0' }, { index: 318, blocks: 0, value: '104324219', participants: 5, cost: '0' } ] ]; console.log(groupAndSum(data));

Explanation解释

  • Object.values() is used to extract the values of the resulting-object from below operations Object.values()用于从以下操作中提取结果对象的值
  • First, the input array is flat tened to remove the nesting首先,将输入数组展flat以去除嵌套
  • Next, .reduce is used to iterate through the array and generate a result-object接下来, .reduce用于遍历数组并生成结果对象
  • acc is the accumulator/aggregator object acc是累加器/聚合器 object
  • Each index is either added into acc as a new key with the value being the actual object每个index要么作为新键添加到acc中,其值为实际 object
  • If the index was already present in acc , then the value and participants props are summed-up.如果index已经存在于acc中,那么将对valueparticipants道具求和。
  • valueB is a new prop to store the BigInt format of value valueB是一个新的 prop 来存储BigInt格式的value

An additional .map() is used to make valueB displayable within the console.log on stack-snippets.附加的.map()用于使valueB可在堆栈片段的console.log中显示。 This may not be required in the original code - so, please ignore.这在原始代码中可能不需要 - 所以请忽略。

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

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