2010-09-29 38 views
5

我有一个项目数组作为在Javascript如下:的Javascript自然排序数组/对象,并保持索引关系

var users = Array(); 

users[562] = 'testuser3'; 
users[16] = 'testuser6'; 
users[834] = 'testuser1'; 
users[823] = 'testuser4'; 
users[23] = 'testuser2'; 
users[917] = 'testuser5'; 

我需要那种阵列输出如下:

users[834] = 'testuser1'; 
users[23] = 'testuser2'; 
users[562] = 'testuser3'; 
users[823] = 'testuser4'; 
users[917] = 'testuser5'; 
users[16] = 'testuser6'; 

注意它是如何按数组的值排序的,并且在数组排序之后维护了数值到索引的关联(这很关键)。我已经找到了解决这个问题的办法,试图做到这一点,但却遇到了困难。

顺便说一句,我知道这在技术上不是一个数组,因为那意味着索引总是迭代0到n,其中n + 1是进行n的计数。但是,您对其进行了定义,但对该项目的要求仍然相同。此外,如果它有所作为,我不使用jquery。

回答

2

使用从评论的想法,我想出了采用以下解决方案。 naturalSort函数是我在google上找到的东西,我修改它以排序多维数组。基本上,我使users数组成为一个多维数组,第一个索引是用户标识,第二个索引是用户名。所以:

users[0][0] = 72; 
users[0][1] = 'testuser4'; 
users[1][0] = 91; 
users[1][1] = 'testuser2'; 
users[2][0] = 12; 
users[2][1] = 'testuser8'; 
users[3][0] = 3; 
users[3][1] = 'testuser1'; 
users[4][0] = 18; 
users[4][1] = 'testuser7'; 
users[5][0] = 47; 
users[5][1] = 'testuser3'; 
users[6][0] = 16; 
users[6][1] = 'testuser6'; 
users[7][0] = 20; 
users[7][1] = 'testuser5'; 

然后我排序的数组得到以下的输出:

users_sorted[0][0] = 3; 
users_sorted[0][1] = 'testuser1'; 
users_sorted[1][0] = 91; 
users_sorted[1][1] = 'testuser2'; 
users_sorted[2][0] = 47; 
users_sorted[2][1] = 'testuser3'; 
users_sorted[3][0] = 72; 
users_sorted[3][1] = 'testuser4'; 
users_sorted[4][0] = 20; 
users_sorted[4][1] = 'testuser5'; 
users_sorted[5][0] = 16; 
users_sorted[5][1] = 'testuser6'; 
users_sorted[6][0] = 18; 
users_sorted[6][1] = 'testuser7'; 
users_sorted[7][0] = 12; 
users_sorted[7][1] = 'testuser8'; 

的代码做,这是下面:

function naturalSort(a, b) // Function to natural-case insensitive sort multidimensional arrays by second index 
{ 

    // setup temp-scope variables for comparison evauluation 
    var re = /(-?[0-9\.]+)/g, 
     x = a[1].toString().toLowerCase() || '', 
     y = b[1].toString().toLowerCase() || '', 
     nC = String.fromCharCode(0), 
     xN = x.replace(re, nC + '$1' + nC).split(nC), 
     yN = y.replace(re, nC + '$1' + nC).split(nC), 
     xD = (new Date(x)).getTime(), 
     yD = xD ? (new Date(y)).getTime() : null; 
    // natural sorting of dates 
    if (yD) 
     if (xD < yD) return -1; 
     else if (xD > yD) return 1; 
    // natural sorting through split numeric strings and default strings 
    for(var cLoc = 0, numS = Math.max(xN.length, yN.length); cLoc < numS; cLoc++) { 
     oFxNcL = parseFloat(xN[cLoc]) || xN[cLoc]; 
     oFyNcL = parseFloat(yN[cLoc]) || yN[cLoc]; 
     if (oFxNcL < oFyNcL) return -1; 
     else if (oFxNcL > oFyNcL) return 1; 
    } 
    return 0; 
} 

// Set values for index 
    var users = Array(); 
    var temp = Array(); 

    users.push(Array('72', 'testuser4')); 
    users.push(Array('91', 'testuser2')); 
    users.push(Array('12', 'testuser8')); 
    users.push(Array('3', 'testuser1')); 
    users.push(Array('18', 'testuser7')); 
    users.push(Array('47', 'testuser3')); 
    users.push(Array('16', 'testuser6')); 
    users.push(Array('20', 'testuser5')); 

// Sort the array 
    var users_sorted = Array(); 
    users_sorted = users.sort(naturalSort); 
+0

嘿,我很高兴你找到了一个有效的答案,但我鼓励你快速看看[我的答案](http://stackoverflow.com/questions/3824392/javascript-natural-sort-array-object - 和 - 维护 - 索引 - 关联/ 3824938#3824938)(我有点迟到游戏!)上面。字符串比较内置于JavaScript中,您可能会发现它是一个更整洁的解决方案。 – s4y 2010-09-29 19:10:19

+0

你也应该看看数组和对象文字(我只在我的回答中简单提及它们)。你可以在你的示例代码中快速创建'users'数组:'var users = [['72','testuser4'],['91','testuser2'],...]' – s4y 2010-09-29 19:12:13

+0

感谢您的支持,它看起来更干净。它支持自然排序吗?这就是我的代码有点滑落的原因。 – user396404 2010-09-29 19:16:39

3

你不能在Javascript中订购这样的数组。您最好的选择是制作地图订单

order = new Array(); 
order[0] = 562; 
order[1] = 16; 
order[2] = 834; 
order[3] = 823; 
order[4] = 23; 
order[5] = 917; 

通过这种方式,您可以拥有任何独立于原始数组中键的顺序。 要对阵列进行排序,请使用自定义排序功能

order.sort(function(a, b) { 
    if (users[a] < users[b]) return -1; 
    else if (users[a] > users[b]) return 1; 
    else return 0; 
}); 

for (var i = 0; i < order.length; i++) { 
    // users[ order[i] ] 
} 

[Demo]

22

数组的元素的顺序是由索引定义。所以,即使你以不同的顺序指定的值,该值将永远保存在其索引的顺序和不确定的指数undefined

> var arr = []; 
> arr[2] = 2; 
> arr[0] = 0; 
> arr 
[0, undefined, 2] 

现在如果你想存储的配对索引和价值,你需要不同的数据结构,也许数组的数组是这样的:

var arr = [ 
    [562, 'testuser3'], 
    [16, 'testuser6'], 
    [834, 'testuser1'], 
    [823, 'testuser4'], 
    [23, 'testuser2'], 
    [917, 'testuser5'] 
]; 

这可以用这个比较函数进行排序:

function cmp(a, b) { 
    return a[1].localeCompare(b[1]); 
} 
arr.sort(cmp); 

的结果是这样的数组:

[ 
    [834, 'testuser1'], 
    [23, 'testuser2'], 
    [562, 'testuser3'], 
    [823, 'testuser4'], 
    [917, 'testuser5'], 
    [16, 'testuser6'] 
] 
0

Array.prototype.sort()有一个可选的自定义比较函数 - 所以,如果你倾倒所有users到一个数组以这种方式[ [562, "testuser3"], [16, "testuser6"] ... etc.]

然后sort该数组具有以下功能:

function(comparatorA, comparatorB) { 
    var userA = comparatorA[1], userB = comparatorB[1] 
    if (userA > userB)  return 1; 
    if (userA < userB)  return -1; 
    if (userA === userB) return 0; 
} 

然后重建你的users对象。 (这会减少你的排序。)或者,将数据保存在新排序的阵列数组中,如果这可以用于你的应用程序。

7

如果我理解正确的问题,您正在使用阵列的方式,他们不打算用于。实际上,初始化风格

// Don't do this! 
var array = new Array(); 
array[0] = 'value'; 
array[1] = 'value'; 
array[2] = 'value'; 

教导关于数组的本质和目的的错误事情。数组是一个有序的项目列表,从零开始索引。创建一个数组正确的方法是用数组文本

var array = [ 
    'value', 
    'value', 
    'value' 
] 

该指数是基于指定项目的顺序上暗示。创建一个数组并设置users[562] = 'testuser3'意味着列表中至少有562个其他用户,并且此时您只有一个知道第563rd的理由。

在你的情况下,该索引是数据,并不代表集合中的项目的顺序。什么你要找的是地图或字典,由平原对象在JavaScript中表示:

var users = { 
    562: 'testuser3', 
    16: 'testuser6', 
    834: 'testuser1', 
    823: 'testuser4', 
    23: 'testuser2', 
    917: 'testuser5' 
} 

现在您所设定的没有订单,但是拥有有意义的钥匙。从这里,你可以按照galambalazs's advice创建对象的关键组成的数组:

var userOrder; 
if (typeof Object.keys === 'function') { 
    userOrder = Object.keys(users); 
} else { 
    for (var key in users) { 
     userOrder.push(key); 
    } 
} 

...然后对其进行排序:

userOrder.sort(function(a, b){ 
    return users[a].localeCompare(users[b]); 
}); 

Here's a demo

+0

@Gumbo我同意!我的答案与此有何不同? – s4y 2010-09-29 19:16:34

+0

没关系。不知何故,我认为你正在尝试对对象的属性进行排序。 – Gumbo 2010-09-29 19:22:06

1

我会使用一次地图为了创建一个新的用户数组, 然后第二次从新数组返回所需的字符串。

var users= []; 
users[562]= 'testuser3'; 
users[16]= 'testuser6'; 
users[834]= 'testuser1'; 
users[823]= 'testuser4'; 
users[23]= 'testuser2'; 
users[917]= 'testuser5'; 

var u2= []; 
users.map(function(itm, i){ 
    if(itm){ 
     var n= parseInt(itm.substring(8), 10); 
     u2[n]= i; 
    } 
}); 
u2.map(function(itm, i){ 
    return 'users['+itm+']= testuser'+i; 
}).join('\n'); 

/*returned value: (String) 
users[834]= testuser1 
users[23]= testuser2 
users[562]= testuser3 
users[823]= testuser4 
users[917]= testuser5 
users[16]= testuser6 
*/ 

如果你想避免任何差距。在输出上使用简单的过滤器 -

u2.map(function(itm, i){ 
    return 'users['+itm+']= testuser'+i; 
}).filter(function(itm){return itm}).join('\n'); 
1

稀疏阵列通常会带来麻烦。你在一个数组对象更好保存键 - 值对(该技术也是有效的JSON):

users = [{ 
    "562": "testuser3" 
},{ 
    "16": "testuser6" 
}, { 
    "834": "testuser1" 
}, { 
    "823": "testuser4" 
}, { 
    "23": "testuser2" 
}, { 
    "917": "testuser5" 
}]; 

至于建议,你可以使用一个for循环排序函数映射到阵列。