以排序的顺序遍历Javascript关联数组


109

假设我有一个Javascript关联数组(又名哈希,又名字典):

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

如何按排序顺序遍历键?如果它有助于简化操作,我什至不需要这些值(它们都只是数字1)。


11
为什么要使用新的Array()构造,然后将其用作对象?
卢克·谢弗

@Luke ..我也是从PHP背景开始的。我已经学会了:)
Alex

20
@卢克:因为我似乎没有经验。您能以正确的方式发布答案吗?
麦克

4
您可以简单地创建任何对象。在Javascript中,字典/“命名数组”和常规对象之间没有区别。因此,您可以使用ab访问a ['b'],反之亦然。创建对象的最短方法是a = {};
罗德韦克

Answers:


124

您不能直接对其进行迭代,但是可以找到所有键,然后对其进行排序。

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;    

function keys(obj)
{
    var keys = [];

    for(var key in obj)
    {
        if(obj.hasOwnProperty(key))
        {
            keys.push(key);
        }
    }

    return keys;
}

keys(a).sort(); // ["a", "b", "z"]

但是,无需将变量“ a”设置为数组。您实际上只是将其用作对象,应该这样创建它:

var a = {};
a["key"] = "value";

28
您应该始终在for循环中检查obj.hasOwnProperty(key)
viam0Zah

3
@Lalit-如果您指的是Torok的评论,那是因为您没有任何东西可以干扰对象的原型,而您不能依赖它。
路加·谢弗

1
+1到Torok。如果答案中包含hasOwnProperty(),那就太好了。
乔恩·昂斯托特

136

您可以使用Object.keys内置方法:

var sorted_keys = Object.keys(a).sort()

(注意:这在不支持EcmaScript5的非常旧的浏览器中不起作用,尤其是IE6、7和8。有关最新统计信息,请参见此


@ michael667可能是因为IE 7和8仍被广泛使用(很遗憾,谢谢您,
女士

1
幸运的是,到目前为止,IE7为0.5%,IE8为8%。
molnarg

3
if (!Object.keys) { Object.keys = function (obj) { var op, result = []; for (op in obj) { if (obj.hasOwnProperty(op) { result.push(op) } } return result }
Jordan Reiter 2013年

我喜欢这个,谢谢。这是我利用此代码的代码,$(Object.keys(list))。map(function(i,e){return n +'='+ list [n];})。get()。join('&'); //网址查询字符串的concat
Elaine

1
2016年更新:这可能是公认的答案
rinogo 2016年

14

您甚至可以将其原型化到对象上:

Object.prototype.iterateSorted = function(worker)
{
    var keys = [];
    for (var key in this)
    {
        if (this.hasOwnProperty(key))
            keys.push(key);
    }
    keys.sort();

    for (var i = 0; i < keys.length; i++)
    {
        worker(this[ keys[i] ]);
    }
}

和用法:

var myObj = { a:1, b:2 };
myObj.iterateSorted(function(value)
{
    alert(value);
} 

3
我对此回答表示赞同,但结果却发现它破坏了jquery :( stackoverflow.com/questions/1827458 / ...,通常认为这是一个非常糟糕的主意,“您永远都不能扩展Object.prototype。它的作用远不止于此。破坏jQuery;它完全破坏了Javascript的“对象作为哈希表”功能。不要这样做。你可以问约翰·雷西格,他会告诉你同样的事情。”
msanjay 2012年

你知道吗?我也讨厌原型:)我从不使用它们,并积极劝阻它们的使用。3.5年前,当我编写此答案时,我有点这样的感觉,但是无论如何都提出了建议……感谢您提供信息。顺便说一句,它不应破坏框架,因为它们在迭代对象时应始终使用hasOwnProperty
Luke Schafer

这是一个使用值而不是它们的键进行排序同时仍保持key -> value关系的示例。
Xeoncross

6

我同意Swingley的回答,并且我认为重要的一点是缺少许多这些更详尽的解决方案。如果仅关注关联数组中的键,并且所有值均为“ 1”,则只需将“键”作为值存储在数组中。

代替:

var a = { b:1, z:1, a:1 };
// relatively elaborate code to retrieve the keys and sort them

用:

var a = [ 'b', 'z', 'a' ];
alert(a.sort());

这样做的一个缺点是,您无法确定是否轻松设置了特定键。有关此问题的答案,请参见javascript函数inArray的答案。提出的解决方案的一个问题是,a.hasValue('key')它会比慢一些a['key']。这可能与您的代码无关紧要。


3

没有简洁的方法可以直接操作Javascript对象的“键”。它不是真的为此设计的。您是否有自由将数据放在比常规对象(或示例代码所建议的数组)更好的数据中?

如果是这样,并且您的问题可以改写为“如果要按排序顺序遍历键,应该使用哪个类似于字典的对象?” 那么您可以开发一个像这样的对象:

var a = {
  keys : new Array(),
  hash : new Object(),
  set : function(key, value) {
    if (typeof(this.hash[key]) == "undefined") { this.keys.push(key); }
    this.hash[key] = value;
  },
  get : function(key) {
    return this.hash[key];
  },
  getSortedKeys : function() {
    this.keys.sort();
    return this.keys;
  }
};

// sample use
a.set('b',1);
a.set('z',1);
a.set('a',1);
var sortedKeys = a.getSortedKeys();
for (var i in sortedKeys) { print(sortedKeys[i]); }

如果您无法控制数据在常规对象中的事实,则此实用程序会将常规对象转换为功能齐全的字典:

a.importObject = function(object) {
  for (var i in object) { this.set(i, object); }
};

为了简单起见,这是一个对象定义(而不是可重用的构造函数)。随意编辑。


2

在第一个for循环中获取键,对其进行排序,然后在第二个for循环中使用排序结果。

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

var b = [];
for (k in a) b.push(k);
b.sort();
for (var i = 0; i < b.length; ++i) alert(b[i]);

2

您可以使用该keys功能从underscore.js库拿到钥匙,那么sort()阵列的方法来对它们进行排序:

var sortedKeys = _.keys(dict).sort();

keys下划线的源代码中的函数:

// Retrieve the names of an object's properties.
// Delegates to **ECMAScript 5**'s native `Object.keys`
_.keys = nativeKeys || function(obj) {
    if (obj !== Object(obj)) throw new TypeError('Invalid object');
    var keys = [];
    for (var key in obj) if (_.has(obj, key)) keys.push(key);
    return keys;
};    

// Shortcut function for checking if an object has a given property directly
// on itself (in other words, not on a prototype).
_.has = function(obj, key) {
    return hasOwnProperty.call(obj, key);
};

0
<script type="text/javascript">
    var a = {
        b:1,
        z:1,
        a:1
    }; // your JS Object
    var keys = [];
    for (key in a) {
        keys.push(key);
    }
    keys.sort();
    var i = 0;
    var keyslen = keys.length;
    var str = '';
    //SORTED KEY ITERATION
    while (i < keyslen) {
        str += keys[i] + '=>' + a[keys[i]] + '\n';
        ++i;
    }
    alert(str);
    /*RESULT:
    a=>1
    b=>1
    z=>1
    */
</script>

0

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;


var keys=Object.keys(a).sort();
for(var i=0,key=keys[0];i<keys.length;key=keys[++i]){
  document.write(key+' : '+a[key]+'<br>');
}


0

我非常喜欢@ luke-schafer的原型构想,但也听听他对原型问题的看法。使用一个简单的函数呢?

function sortKeysAndDo( obj, worker ) {
  var keys = Object.keys(obj);
  keys.sort();
  for (var i = 0; i < keys.length; i++) {
     worker(keys[i], obj[keys[i]]);
  }
}

function show( key, value ) {
  document.write( key + ' : ' + value +'<br>' );
}

var a = new Array();
a['b'] = 1;
a['z'] = 1;
a['a'] = 1;

sortKeysAndDo( a, show);

var my_object = { 'c': 3, 'a': 1, 'b': 2 };

sortKeysAndDo( my_object, show);

这似乎消除了原型的问题,并且仍然为对象提供了排序的迭代器。我并不是真正的JavaScript专家,所以我很想知道这个解决方案是否存在我错过的隐藏缺陷。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.