Javascript自然排序数组/对象并维护索引关联

发布于 2024-09-25 07:05:12 字数 631 浏览 2 评论 0原文

我有一个 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。

I have an array of items as follows in Javascript:

var users = Array();

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

I need to sort that array to get the following output:

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

Notice how it is sorted by the value of the array and the value-to-index association is maintained after the array is sorted (that is critical). I have looked for a solution to this, tried making it, but have hit a wall.

By the way, I am aware that this is technically not an array since that would mean the indices are always iterating 0 through n where n+1 is the counting number proceeding n. However you define it, the requirement for the project is still the same. Also, if it makes a difference, I am NOT using jquery.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(8

谢绝鈎搭 2024-10-02 07:05:12

数组元素的顺序由索引定义。因此,即使您以不同的顺序指定值,这些值也将始终按照其索引的顺序存储,并且未定义的索引是未定义

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

The order of the elements of an array is defined by the index. So even if you specify the values in a different order, the values will always be stored in the order of their indices and undefined indices are undefined:

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

Now if you want to store the pair of index and value, you will need a different data structure, maybe an array of array like this:

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

This can be sorted with this comparison function:

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

The result is this array:

[
    [834, 'testuser1'],
    [23, 'testuser2'],
    [562, 'testuser3'],
    [823, 'testuser4'],
    [917, 'testuser5'],
    [16, 'testuser6']
]
花海 2024-10-02 07:05:12

如果我正确理解了这个问题,您正在以不应该使用的方式使用数组。事实上,初始化风格

// 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 个其他用户,并且您有理由只知道此时第563次。

在您的情况下,索引是数据,并不代表集合中项目的顺序。您正在寻找的是地图或字典,在 JavaScript 中由普通对象表示:

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

现在您的集合没有顺序,但具有有意义的键。从这里,您可以遵循 galambalazs 的建议 创建对象键的数组:

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

这是一个演示< /a>

If I understand the question correctly, you're using arrays in a way they are not intended to be used. In fact, the initialization style

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

teaches wrong things about the nature and purpose of arrays. An array is an ordered list of items, indexed from zero up. The right way to create an array is with an array literal:

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

The indexes are implied based on the order the items are specified. Creating an array and setting users[562] = 'testuser3' implies that there are at least 562 other users in the list, and that you have a reason for only knowing the 563rd at this time.

In your case, the index is data, and is does not represent the order of the items in the set. What you're looking for is a map or dictionary, represented in JavaScript by a plain object:

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

Now your set does not have an order, but does have meaningful keys. From here, you can follow galambalazs's advice to create an array of the object's keys:

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

…then sort it:

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

Here's a demo

地狱即天堂 2024-10-02 07:05:12

你不能在 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] ]
}

[演示]

You can't order arrays like this in Javascript. Your best bet is to make a map for order.

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

In this way, you can have any order you want independently of the keys in the original array.
To sort your array use a custom sorting function.

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]

原来分手还会想你 2024-10-02 07:05:12

根据评论中的想法,我想出了以下解决方案。 naturalSort 函数是我在谷歌上找到的,我修改它来对多维数组进行排序。基本上,我将用户数组设置为多维数组,第一个索引是用户 ID,第二个索引是用户名。所以:

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

Using the ideas from the comments, I came up with the following solution. The naturalSort function is something I found on google and I modified it to sort a multidimensional array. Basically, I made the users array a multidimensional array with the first index being the user id and the second index being the user name. So:

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

I then sorted the array to get the following output:

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

The code to do this is below:

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);
水中月 2024-10-02 07:05:12

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

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');

I'd use map once to make a new array of users,
then a second time to return the string you want from the new array.

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
*/

If you want to avoid any gaps. use a simple filter on the output-

u2.map(function(itm, i){
    return 'users['+itm+']= testuser'+i;
}).filter(function(itm){return itm}).join('\n');
活泼老夫 2024-10-02 07:05:12

稀疏数组通常会带来麻烦。最好将数组中的键值对保存为对象(此技术也是有效的 JSON):

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

根据建议,您可以使用 for 循环将排序函数映射到数组。

Sparse arrays usually spell trouble. You're better off saving key-value pairs in an array as objects (this technique is also valid JSON):

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

As suggested, you can use a for loop to map the sorting function onto the array.

请持续率性 2024-10-02 07:05:12

Array.prototype.sort() 采用可选的自定义比较函数 - 因此,如果您以这种方式将所有 users 转储到数组中 [ [562, "testuser3"], [16, "testuser6"] 。 .. 等]

然后使用以下函数对该数组进行排序

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 对象。 (这将使您失去排序。)或者,将数据保留在新排序的数组数组中,如果这适用于您的应用程序。

Array.prototype.sort() takes an optional custom comparison function -- so if you dump all of your users into an array in this manner [ [562, "testuser3"], [16, "testuser6"] ... etc.]

Then sort this array with the following function:

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

Then rebuild your users object. (Which will loose you your sorting.) Or, keep the data in the newly sorted array of arrays, if that will work for your application.

债姬 2024-10-02 07:05:12

结果为数组数组的 oneliner:

用于按键排序。

let usersMap = users.map((item, i) => [i, item]).sort((a, b) => a[0] - b[0]);

用于按值排序。 (适用于原始类型)

let usersMap = users.map((item, i) => [i, item]).sort((a, b) => a[1] - b[1]);

A oneliner with array of array as a result:

For sorting by Key.

let usersMap = users.map((item, i) => [i, item]).sort((a, b) => a[0] - b[0]);

For sorting by Value. (works with primitive types)

let usersMap = users.map((item, i) => [i, item]).sort((a, b) => a[1] - b[1]);
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文