根据属性分组对javascript数组进行排序

根据属性分组对javascript数组进行排序,javascript,arrays,grouping,Javascript,Arrays,Grouping,我使用从搜索Web服务返回的json对象数组来提供jQuery.ui自动完成,在这里我使用根据对象的“族”对对象进行分组 该算法使用一个列表,其中组已经被很好地排序,这是我目前无法做到的,因此我希望在客户端组织数据。例如,如果我有以下数组: var resultsArray = [ {"cat": "Category #1", "Id": "10"}, {"cat": "Category #2", "Id": "28"}, {"cat": "Category #1", "Id": "11"},

我使用从搜索Web服务返回的json对象数组来提供jQuery.ui自动完成,在这里我使用根据对象的“族”对对象进行分组

该算法使用一个列表,其中组已经被很好地排序,这是我目前无法做到的,因此我希望在客户端组织数据。例如,如果我有以下数组:

var resultsArray = [
{"cat": "Category #1", "Id": "10"},
{"cat": "Category #2", "Id": "28"},
{"cat": "Category #1", "Id": "11"},
{"cat": "Category #2", "Id": "21"},
{"cat": "Category #1", "Id": "13"}
];
我想调用resultsArray上的一个方法,以便返回

resultsArray = [
{"cat": "Category #1", "Id": "10"},
{"cat": "Category #1", "Id": "11"},
{"cat": "Category #1", "Id": "13"},
{"cat": "Category #2", "Id": "28"},
{"cat": "Category #2", "Id": "21"}
];
按cat属性分组,同时保留现有顺序

首先,我尝试对数组使用排序方法,方法是返回数组中可以找到我尝试分组依据的值的位置(假设acs.groupBy包含分组属性的名称:

items.sort(function(a, b) {
    var aValue = a[acs.groupBy],
    bValue = b[acs.groupBy];
    var indexOfAValue = 0; // should be sthing like items.indexWhere(item[acs.groupBy] === aValue)
    var indexOfBValue = 0; // same thing
    return indexOfAValue - indexOfBValue;
});
with indexOfAValue将是数组中找到A的分组属性的第一个位置,但是我找不到一个简单的方法来获取和缓存这个值(数组的indexOf匹配整个对象)。你知道如何获取它吗


编辑

看起来我举了一个错误的例子:) 我不想对类别进行排序。如果类别#2发生在类别#1之前,我希望保留此信息,以便

var resultsArray = [
    {"cat": "Category #3", "Id": "39"},
    {"cat": "Category #2", "Id": "28"},
    {"cat": "Category #1", "Id": "11"},
    {"cat": "Category #2", "Id": "21"},
    {"cat": "Category #1", "Id": "18"}
]
将变成(请注意,尽管我根据类别对项目进行了分组,但我没有更改类别出现的顺序,也没有根据其id更改组内的项目顺序)


这就是为什么我在上面的示例中尝试按indexOf(category)排序的原因

看起来您只是在寻找一个正常的稳定排序?原生JS排序在大多数浏览器中都是稳定的(过去2年左右的所有现代浏览器),因此:

items.sort( function( a, b ){
    return a.Id - b.Id;
} );
通常会工作,但并非在所有浏览器中都稳定,因此要做到这一点,请执行以下操作:

for( var i=0... ){
   items[i].index = i;
}
items.sort( function( a, b ){
    return ( a.Id != b.Id ) ? ( a.Id - b.Id ) : ( a.index - b.index );
}

它按Id排序,然后按原始顺序排序。

您的方法正确,您的
排序功能不需要太复杂:

function group(array) {
    var i, categories = {};
    /* Build a map of categories and minimum indices: */
    for (i = 0; i < resultsArray.length; i++) {
        if (!categories[resultsArray[i].cat]) {
            categories[resultsArray[i].cat] = i;
        }
    }

    /* Sort the array using the minimum index: */
    return resultsArray.sort(function(one, other) {
        return categories[one.cat] - categories[other.cat];
    });
}
功能组(数组){
变量i,类别={};
/*建立类别和最小索引的地图:*/
对于(i=0;i
示例:


这应该让你开始。不幸的是,该函数在数组中循环了两次(这显然不是最优的)。

我强烈建议您看看下划线的一些数组功能:我将尝试了解这种稳定排序。我会尽快回来并给出结果:)这只是意味着当值相同时,它会保持原始顺序。您的方法是正确的(即保持不同项的索引),但我显然需要一种方法来跟踪列表中的原始索引(例如,通过使用哈希表)。谢谢你为我指明了正确的方向,这确实符合最初的指示。我曾尝试实施你的解决方案,但显然我没有正确理解它。从您所看到的排序没有产生正确的输出。@samy:我有一个初步的解决方案。这不是最好的,但希望它能让你开始。让我知道你的想法!我得到了同样的结果:我希望有一种方法可以一次性完成,但我找不到。您的答案是正确的:)这在某些浏览器中无法保持原始顺序
function group(array) {
    var i, categories = {};
    /* Build a map of categories and minimum indices: */
    for (i = 0; i < resultsArray.length; i++) {
        if (!categories[resultsArray[i].cat]) {
            categories[resultsArray[i].cat] = i;
        }
    }

    /* Sort the array using the minimum index: */
    return resultsArray.sort(function(one, other) {
        return categories[one.cat] - categories[other.cat];
    });
}