【问题标题】:Create a new array from another array从另一个数组创建一个新数组
【发布时间】:2012-12-16 07:36:46
【问题描述】:

我有两个数组。第一个包含地点和一些关于它们的信息。它是一个多维数组,分三步:

  • 第 1 步:类别(例如标题、日期等...)。
  • 第 2 步:实际地点
  • 第 3 步:经纬度(在类别坐标下)

    places[0][0] = 'Stockholm';     // Header
    places[0][1] = 'Karlstad';
    places[0][2] = 'Borgholm';
    places[1][0] = '2012-05-25';    // Date
    places[1][1] = '2012-06-12';    
    places[1][2] = '2012-05-14'
    places[2][0] = 'Lorum ipsum lorum ipsum lorum ipsum';       // Description
    places[2][1] = 'Ipsum lorum lorum ipsum lorum ipsum';
    places[2][2] = 'Forum Lorum Porum';
    places[3][0][0] = '56,123342';      // Latitude
    places[3][0][1] = '49,123123';      // Longitude
    places[3][1][0] = '23,543231';
    places[3][1][1] = '45,955432';
    places[3][2][0] = '34,123459';
    places[3][2][1] = '45,325198';
    ...and so on...
    

第二个数组包含搜索结果,即匹配搜索的地点。我想要做的是用信息创建一个新数组 在第一个数组中,但仅适用于第二个数组中的元素(因此在上面的示例中,只有地方 [1] ('Karlstad') 应该在 新数组。

我还希望新数组具有新结构。而不是第一级中的类别,我想要第一级中的位置(参见下面的示例)。

results = [1, 15, 17, 19, 32, 91, 102, 103];

newPlaces[0][0] = 'Karlstad';
newPlaces[1][0] = 'Kalmar';
newPlaces[2][0] = 'Luleå';
newPlaces[3][0] = 'Överkalix';
newPlaces[4][0] = 'Malmö';
newPlaces[5][0] = 'Ystad';
newPlaces[6][0] = 'Linköping'
...and so on...

最好和最简单的方法是什么? 我想我应该使用 for 循环,如下所示(不起作用)?

for (var i = 0; i < results.length; i++) {
    newPlaces[i][0] = places[0][results[i]];
    newPlaces[i][1] = places[1][results[i]];
    newPlaces[i][2] = places[2][results[i]];
    newPlaces[i][3] = places[3][results[i]];
}

提前非常感谢!

【问题讨论】:

  • 你真的应该真正真正地使用 JSON 来处理这种东西,它对机器和人类来说会容易得多。您可以轻松地将其转换为 JSON,反之亦然。
  • +1 @Wololo 的建议。通过使用 JSON 和/或 JS 对象,这种类型的东西变得更加可读。

标签: javascript jquery arrays loops multidimensional-array


【解决方案1】:

考虑到您拥有的多维结构,for 循环可能是最简单的。你只需要声明你的变量,并添加一些简写,以便于阅读代码。应该这样做:

var newPlaces = [];
for (var i = 0; i < results.length; i++) {
    var id = results[i]
    newPlaces[i] = [
        places[0][id], 
        places[1][id],
        places[2][id],
        places[3][id],
        places[4][id]
    ];
}

由于您使用 jQuery 标记了它,因此您可以使用jQuery.each 使您的代码更简单一些(但不像@Marcus Ekwall 提到的那样性能降低 > 90%):

var newPlaces = [];
$.each(results, function(i, id) {
    newPlaces[i] = [
        places[0][id], 
        places[1][id],
        places[2][id],
        places[3][id],
        places[4][id]
    ];
});

在重要的时候牢记性能。 jQuery 非常方便,可以让您更快/更轻松地编写代码,但如果您不小心,它确实会降低您的网站/应用程序的速度。

【讨论】:

  • 以上是test case。 @Levi 必须在我之前回答,所以我不会添加另一个答案。
  • 不要使用 .each 作为内联 for 循环的替代品。可读性的微小提升(在这种情况下)不值得性能的巨大下降。我们在这里谈论about ~90% slower :)
  • 我完全同意 Marcus,在大多数情况下包括这个(因为我们不知道我们正在与多少地方合作)。但是,当我知道自己正在处理一个小型数据集时,便利性和可读性通常对我来说是值得的。
  • 我相信大多数人缺乏相关知识,并且尽可能使用 jQuery 和其他框架,而不考虑性能。但只要你知道它的影响,我不会反对。
【解决方案2】:

这个怎么样:

var places = [ ];

...

var newPlaces = [ ];
var placesArray;

for (var i = 0; i < places[0].length; i++) // loop through the headers first
{
  placesArray = [ ];

  for (var j = 0; j < places.length; j++) // make sure we loop through the other properties too
  {
    placesArray.push(
      places[j][i]
    );
  }

  newPlaces.push(
    placesArray
  );
}

console.log(places, placesArray);

至少这样你就不会被限制在你的数组有多大。

【讨论】:

    【解决方案3】:

    要添加到@Levi 的答案,您还可以使用 ES5 地图:

    使用原生 Array.prototype.map:

    newPlaces = results.map(function(result) {
        return [
            places[0][result],
            places[1][result],
            places[2][result],
            places[3][result]
        ];
    });
    

    使用手工地图:

    感谢 Marcus 在下方评论指出原生地图的性能问题。

    显然,替代方案是一个自定义版本的映射,它掩盖了 for 循环。到目前为止,它似乎比简单地使用 for 循环做得好一点,但我没有解释为什么,也没有关系。

    // Custom map function
    function map(arr, func) {
        var newArr = [];
        var cnt = arr.length;
        var arrLen = arr.length;
        for (; cnt; cnt--) {
           newArr.push(func(arr[arrLen - cnt]));    
        }
        return newArr;
    }
    
    newPlaces = map(results, function(result) {
        return [
            places[0][result],
            places[1][result],
            places[2][result],
            places[3][result]
        ];
    });
    

    显然,代码仍然像使用原生地图一样干净,但性能提升了十倍。它也比 for 循环稍微快一些。

    这是一个使用各种方法执行 1M 次迭代的小提琴:

    http://jsfiddle.net/6wArq/3/

    编辑:

    顺便说一句,对于那些老旧的浏览器甚至没有Array.prototype.map,您可以使用ES5 shim 来添加此功能。

    EDIT2:

    在 MDN 上查看 documentation 以获取 Array.prototype.map

    EDIT3:

    好的,自定义映射并不比 for 循环快,所以假设它的性能也一样。

    EDIT4:

    自定义映射的最终版本使其执行速度始终比增加计数器的常用 for 循环更快。我假设递减计数器的 for 循环的性能与最终的自定义映射函数一样好。

    【讨论】:

    • 使用.map 非常棒,但performs horribly compared to an inline for-loop(在我的系统上慢了~%80),所以我反对在这种特定情况下使用这种方法。
    • @MarcusEkwall:我已经更新了答案以包含自定义版本的地图,它的性能甚至比 for 循环更好。 ;)
    • @bvukleic 不错!原生 Array.map 比 JS 实现慢,这很愚蠢。哦,好吧,当引擎优化突破使用 C 绑定的开销时会发生这种情况(PCRE 也是如此)。太糟糕了,回归测试并没有像这样的性能提升;)
    • @MarcusEkwall:是的,我一直认为本机代码应该运行得更快,特别是因为地图之类的东西可以并行化等等。
    • @bvukleic 这个假设是正确的,只要你不计算使用 C 绑定的开销。这可能就是为什么它们仍然以这种方式实现的原因:P
    【解决方案4】:

    我怀疑您可能在这方面遇到困难的原因在于您滥用数组。很简单,这里使用的数据结构不正确。信息可以用 JSON 更符合逻辑地表示。

    var places = [
        {
            "Header": "Stockholm",
            "Date": "2012-05-25",
            "Description": "Lorum ipsum lorum ipsum lorum ipsum",
            "Latitude": "56,123342",
            "Longitude": "49,123123"
        },
        {
            "Header": "Karlstad",
            "Date": "2012-06-12",
            "Description": "Lorum ipsum lorum ipsum lorum ipsum",
            "Latitude": "23,543231",
            "Longitude": "45,955432"
        }
    ];​
    

    那么你的for 循环就很简单了:

    var newPlaces = [];
    for (var i = 0; i < results.length; i++) {
        newPlaces[i] = places[results[i]];
    }
    

    产生一个简单的地点对象集合,与上面的形式相同。

    【讨论】:

      猜你喜欢
      • 2017-05-06
      • 2013-08-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-04-16
      相关资源
      最近更新 更多