【问题标题】:Convert multi-dimensional array into single array (Javascript)将多维数组转换为单个数组(Javascript)
【发布时间】:2015-12-24 03:21:12
【问题描述】:

我有一个对象数组(来自 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) 继承第一个实例的值并忽略其余部分。

经过几次失败的尝试和大量的在线搜索,我从this answer 得到了一个想法,像这样循环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>

【问题讨论】:

    标签: javascript arrays object multidimensional-array


    【解决方案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(我确实对你的帖子投了赞成票,但我没有足够的代表来投票。)
    【解决方案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, ' ');
    &lt;pre id="result"&gt;&lt;/pre&gt;

    【讨论】:

    • 谢谢!这也很有效。尽管您还在代码中包含了“位置”,但我不需要将其堆叠在数组中,但我只是删除了该行,它给出了所需的结果。我把它保存在这里:jsfiddle.net/kqtj315e
    • 很高兴我能提供帮助。我意识到映射/连接可以大大简化(请参阅编辑后的答案)
    • 在这里尝试了所有答案之后,我实际上决定使用这种方法,因为对于我的所有其余代码,这会产生最简单的逻辑,结果也是最短的。 (但是,我遇到了另一个问题stackoverflow.com/questions/32806786/… :))
    【解决方案3】:

    这样就可以了:

    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 的解决方案。我也在这里保存了这个jsfiddle.net/3wp1j9rs
    【解决方案4】:

    你可以改变这些行:

     res[value.id].type = [res[value.id].type, value.type];
     res[value.id].funds = [res[value.id].funds, value.funds];
    

    到这里:

    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];
    

    【讨论】:

    • 非常感谢,这正是我想要的!优雅而快速。 (为了将来参考,我把完整的代码保存在一个小提琴中:jsfiddle.net/3g444sy9
    猜你喜欢
    • 1970-01-01
    • 2011-10-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多