将多维数组转换为单一数组(Javascript)

5

我有一个对象数组(来自XLSX.js解析器,因此其长度和内容会有所不同),表示已授予项目的拨款。

简化后,它看起来像这样:

var grants = [
    { id: "p_1", location: "loc_1", type: "A", funds: "5000" },
    { id: "p_2", location: "loc_2", type: "B", funds: "2000" },
    { id: "p_3", location: "loc_3", type: "C", funds:  "500" },
    { id: "p_2", location: "_ibid", type: "D", funds: "1000" },
    { id: "p_2", location: "_ibid", type: "E", funds: "3000" }
];

我需要将它们合并到一个新的数组中,新数组应该长这样:
var projects = [
    { id: "p_1", location: "loc_1", type: "A", funds: "5000" },
    { id: "p_2", location: "loc_2", type: ["B", "D", "E"], funds: ["2000", "1000", "3000"] },
    { id: "p_3", location: "loc_3", type: "C", funds: "500" }
];

id相同时,将合并对象并将它们的一些关键值(在示例中为typefunds)组合成一个简单的子数组。合并对象中的其他键(location)从第一个实例继承值并忽略其余部分。

经过多次失败尝试和大量在线搜索后,我从这个答案中得到了一个想法,以以下方式循环遍历grants

var res = {};

$.each(grants, function (key, value) {
    if (!res[value.id]) {
        res[value.id] = value;    
    } else {
        res[value.id].type = [res[value.id].type, value.type];
        res[value.id].funds = [res[value.id].funds, value.funds];
    }
});

var projects = []
projects = $.map( res, function (value) { return value; } );

它实际上运行得非常完美,但是由于我需要一个数组,我从上面提到的答案中删除了 .join(',') ,这反过来又创建了我现在似乎无法解决的问题。如果至少有三个项,子数组会在彼此嵌套!我有点理解为什么(循环),但我想知道是否有一种方法可以将对象内所有这些小多维数组转换为单个数组(例如:type: ["B", "D", "E"])?

var grants = [
    { id: "p_1", location: "loc_1", type: "A", funds: "5000" },
    { id: "p_2", location: "loc_2", type: "B", funds: "2000" },
    { id: "p_3", location: "loc_3", type: "C", funds:  "500" },
    { id: "p_2", location: "_ibid", type: "D", funds: "1000" },
    { id: "p_2", location: "_ibid", type: "E", funds: "3000" }
];

var res = {};

$.each(grants, function (key, value) {
    if (!res[value.id]) {
        res[value.id] = value;    
    } else {
        res[value.id].type = [res[value.id].type, value.type];
        res[value.id].funds = [res[value.id].funds, value.funds];
    }
});

var projects = []
projects = $.map( res, function (value) { return value; } );


$("pre").html(JSON.stringify(projects,null,2));
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<pre id="json"></pre>

4个回答

2

这个想法可行吗?

var grants = [
    { id: "p_1", location: "loc_1", type: "A", funds: "5000" },
    { id: "p_2", location: "loc_2", type: "B", funds: "2000" },
    { id: "p_3", location: "loc_3", type: "C", funds:  "500" },
    { id: "p_2", location: "_ibid", type: "D", funds: "1000" },
    { id: "p_2", location: "_ibid", type: "E", funds: "3000" }
];
var joined = [];

// map and push to joined
grants.map(
  function (v) {
    if (!(v.id in this)) {
      this[v.id] = v;
      joined.push(v);
    } else {
      var current = this[v.id];
      current.type = [v.type].concat(current.type);
      current.funds = [v.funds].concat(current.funds);
    }
  }, {}
);

// show it
document.querySelector('#result').textContent =
   JSON.stringify(joined, null, ' ');
<pre id="result"></pre>


谢谢!这也很好用。虽然您在代码中还包括了“位置”这个我不需要放入数组的内容,但我只是删除了那一行,就得到了想要的结果。我已经将它保存在这里:http://jsfiddle.net/kqtj315e/ - tmrk
很高兴我能提供帮助。我意识到映射/连接可以大大简化(请参见编辑后的答案)。 - KooiInc
在尝试了所有这里的答案之后,我最终决定采用这种方法,因为与我的所有其他代码相比,这产生了最简单的逻辑,而且也是最短的。 (但是,我还遇到了另一个问题http://stackoverflow.com/questions/32806786/removing-empty-object-keys-in-an-array-of-objects :)) - tmrk

1
我提出这个解决方案。它具有查找功能,如果索引存在于项目数组中,则将类型和资金推送到该数组中;如果不存在,则将类型和资金属性更改为包含值的数组,该值作为第一个元素。

var grants = [
        { id: "p_1", location: "loc_1", type: "A", funds: "5000" },
        { id: "p_2", location: "loc_2", type: "B", funds: "2000" },
        { id: "p_3", location: "loc_3", type: "C", funds: "500" },
        { id: "p_2", location: "_ibid", type: "D", funds: "1000" },
        { id: "p_2", location: "_ibid", type: "E", funds: "3000" }
    ],
    project = [];

grants.forEach(function (a) {
    !project.some(function (b, i) {
        if (a.id === b.id) {
            project[i].type.push(a.type);
            project[i].funds.push(a.funds);
            return true;
        }
    }) && project.push({ id: a.id, location: a.location, type: [a.type], funds: [a.funds] });
});
document.write('<pre>' + JSON.stringify(project, 0, 4) + '</pre>');


谢谢你!这也会从只有一个项目的数组中创建一个数组,这在我的项目中可能很有用。我也喜欢你摆脱了不必要的jQuery! :P(我已经为您的帖子投票了,但我没有足够的声望来显示我的投票。) - tmrk

1
你可以只更改这些行:
 res[value.id].type = [res[value.id].type, value.type];
 res[value.id].funds = [res[value.id].funds, value.funds];

To this:

Array.isArray(res[value.id].type) ? res[value.id].type.push(value.type) : res[value.id].type = [res[value.id].type, value.type];
Array.isArray(res[value.id].funds) ? res[value.id].funds.push(value.funds) : res[value.id].funds = [res[value.id].funds, value.funds];

非常感谢,这正是我想要的!优雅而快速。(供参考,我在fiddle中保存了完整的代码:http://jsfiddle.net/3g444sy9/) - tmrk

1
这样就可以了:
var tempArr = [];
var result  = [];
for(i in grants){
  var rowObj = grants[i];
  var idPos  = tempArr.indexOf(rowObj.id);
  if(idPos > -1){
     result[idPos].type.push(rowObj.type);
     result[idPos].funds.push(rowObj.funds);
  }else{
    tempArr.push(rowObj.id);
    rowObj.type  = [rowObj.type]
    rowObj.funds = [rowObj.funds]
    result.push(rowObj);
  }
}
console.log(result);

谢谢!这个也可以。逻辑让我想起了@nina-scholz的解决方案。我也把它保存在这里http://jsfiddle.net/3wp1j9rs/。 - tmrk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接