从Node.JS中的平面集中提取分层数据集

时间:2019-04-11 23:17:05

标签: javascript arrays node.js

我正在尝试使用Javascript / Node.JS将平面数据集中的所有项目组合在一起以形成分层数据集。

我有一个解决方案,但我认为这不是最优雅的,它可能会得到改善。

我在Find all objects with matching Ids javascript

中给出了答案的解决方案

我的数据集如下:

let data = [{cid: 1, clbl: 'Rush Shipping', pid:5, plbl: 'FedEx'},
        {cid: 2, clbl: 'Standard Shipping', pid:5, plbl: 'FedEx'},
        {cid: 3, clbl: 'First Class', pid:8, plbl: 'USPS'},
        {cid: 4, clbl: 'Std', pid:9, plbl: 'DHL'},
        {cid: 5, clbl: 'Canada Post', pid:1, plbl: 'Canada Post'},
       ];

我希望我的输出是这样的:

[ { pid: 5,
    plbl: 'FedEx',
    methods: [
       {
         cid: 1,
         clbl: 'Rush Shipping',
       },
       {
         cid: 2,
         clbl: 'Standard Shipping',
       },
   },
   { pid: 8,
    plbl: 'USPS',
    methods: [
       {
         cid: 3,
         clbl: 'First Class',
       },
   },
   { pid: 9,
    plbl: 'DHL',
    methods: [
       {
         cid: 4,
         clbl: 'Std',
       },
   },
   { pid: 1,
    plbl: 'Canada Post',
    methods: [
       {
         cid: 5,
         clbl: 'Canada Post',
       },
   },
 ]

我整理了一些可行的代码,但我想有一种更优化的方法可以做到这一点,并认为我会将其放入SO社区。

这是我的解决方法:

var roots = [];

var all = {};
data.forEach(function(item) {
    all[item.pid] = item;
})
Object.keys(all).forEach(function(pid) {
  var items = data.filter(x => x.pid == pid);
  var addItem = {};
    items.forEach(function(item, j) {
    if (j === 0){
        addItem = {pid:item.pid, label:item.plbl, methods:[]};
     }
    addItem.methods.push({cid: item.cid, label: item.clbl});
    });
  roots.push(addItem);
})
console.log(roots);

2 个答案:

答案 0 :(得分:1)

从内存/速度的角度来看,我不认为这是“最佳化”的,但要短一些。

let new_data = Object.values(data.reduce(function(o, d) {
    o[d.pid] = o[d.pid] || {pid: d.pid, plbl: d.plbl, methods:[]};
    o[d.pid].methods.push({cid: d.cid, clbl: d.clbl});
    return o;
}, {}));

基本上可以利用reduce方法来构建一个组合的all对象。然后使用Object.values()根据存储在all对象中的值创建一个数组,而不是手动推送它们。

答案 1 :(得分:0)

我将建议一种更困难而不是更简单的方法。但这还将涉及创建许多可重用的功能。

我是Ramda编程库的忠实拥护者(免责声明:我是它的作者之一。)因此,当我尝试执行此类操作时,我会接触Ramda。而且我发现,只需将多个简单的步骤组合在一起,就可以在其REPL中进行编码。

我与Ramda的通行证如下:

const transform = pipe(
  groupBy(prop('pid')),
  map(applySpec({
    pid: path([0, 'pid']),
    plbl: path([0, 'plbl']),
    methods: project(['cid', 'clbl'])
  })),
  values
)

let data = [{cid: 1, clbl: 'Rush Shipping', pid:5, plbl: 'FedEx'}, {cid: 2, clbl: 'Standard Shipping', pid:5, plbl: 'FedEx'}, {cid: 3, clbl: 'First Class', pid:8, plbl: 'USPS'}, {cid: 4, clbl: 'Std', pid:9, plbl: 'DHL'}, {cid: 5, clbl: 'Canada Post', pid:1, plbl: 'Canada Post'}];

console.log(transform(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<script src="https://bundle.run/ramda@0.26.1"></script><script>
const {pipe, groupBy, prop, map, applySpec, path, project, values} = ramda   </script>

其中的所有功能都相当可重用。因此,我可以通过包含每个函数的简单版本来启动自己的小程序库。然后这段代码同样简单,我可以在应用程序的其他地方使用这些功能。

这是使用这些功能的简化版本的另一种方法。 (请注意,我在这里将map重命名为mapObject,因为我编写的任何此类库都将包含一个简单的map函数,其功能类似于Array.prototype.map。在Ramda中,一个函数涵盖了他们两个,但这不是那么简单。)

// In my utility library
const pipe = (fn1, ...fns) => (...args) =>
  fns.reduce((r, fn) => fn(r), fn1(...args))
const prop = (name) => (obj) => 
  obj[name]
const values = (obj) => 
  Object.values(obj)
const mapObject = (fn) => (obj) => 
  Object.keys(obj).reduce((a, k) => ({...a, [k]: fn(obj[k])}), {})
const groupBy = (fn) => (xs) =>
  xs.reduce((a, x) => ({...a, [fn(x)]: (a[fn(x)] || []).concat(x)}), {})
const applySpec = (s) => (o) =>
  Object.entries(s).reduce((a, [k, fn]) => ({...a, [k]: fn(o)}), {})
const path = (ns) => (obj) =>
  ns.reduce((v, n) => (v[n] || {}), obj)
const project = (ns) => (xs) =>
  xs.map(x => ns.reduce((a, n) => ({...a, [n]: x[n]}), {}))

// In current module
const transform = pipe(
  groupBy(prop('pid')),
  mapObject(applySpec({
    pid: path([0, 'pid']),
    plbl: path([0, 'plbl']),
    methods: project(['cid', 'clbl'])
  })),
  values
)

let data = [{cid: 1, clbl: 'Rush Shipping', pid:5, plbl: 'FedEx'}, {cid: 2, clbl: 'Standard Shipping', pid:5, plbl: 'FedEx'}, {cid: 3, clbl: 'First Class', pid:8, plbl: 'USPS'}, {cid: 4, clbl: 'Std', pid:9, plbl: 'DHL'}, {cid: 5, clbl: 'Canada Post', pid:1, plbl: 'Canada Post'}];

console.log(transform(data))
.as-console-wrapper { max-height: 100% !important; top: 0; }
<!-- Look, Ma, no Ramda -->

所有这些功能都可用in the Ramda documentation。其中许多功能更为复杂,但是这些简单的实现将使我们走很长一段路。

相关问题