在JavaScript中按值对字典进行排序

69

这是我的字典:

const dict = {
  "x" : 1,
  "y" : 6,
  "z" : 9,
  "a" : 5,
  "b" : 7,
  "c" : 11,
  "d" : 17,
  "t" : 3
};

我需要一种方法来对我的dict字典进行从最小到最大或者从最大到最小的排序,或者如果有一个包含排好序的键的数组也可以。但是我不知道如何使用Javascript做这样的事情。我以前用Python做过这样的事情,像这样:
import heapq
from operator import itemgetter

thirty_largest = heapq.nlargest(8, dict.iteritems(), key=itemgetter(1))

我在谷歌上搜索了一下,发现数组有sort()函数,但字典没有。所以我的问题是:如何对字典进行排序或获取前5个最大值?


2
在JS中,你有对象(不是字典)。关于这个主题有一些问题在SO上... 例如,你可以看一下:按属性值排序JavaScript对象 - Samuel Caillerie
OP希望按键排序,但是链接问题的答案应该很容易调整为按键而不是按值进行排序。 - Emil Lundberg
1
似乎是按值排序的,看最后一行:获取前5个最大的... - Samuel Caillerie
1
由于JavaScript中的对象(字典)没有顺序,因此对这样的东西进行排序是没有意义的。因此,我强烈建议您将标题更改为“如何获取前5个最大值”,以避免人们关闭此问题。 - slebetman
3
他说他想按键对一个字典进行排序。在JS中没有字典,因此我们可以构建一个按键/值排序的结构来满足他的需求,这个结构看起来像一个“字典”。不需要改变他的问题。我认为这是其他语言用户常遇到的问题,所以我认为应该保留原标题。 - Rayjax
2
Object.keys(dict).sort() 返回一个按键排序的数组。当你需要时,你可以使用它来循环遍历字典。 - Sebastien C.
9个回答

112
在JavaScript中可能不是很直观。

var dict = {
  "x": 1,
  "y": 6,
  "z": 9,
  "a": 5,
  "b": 7,
  "c": 11,
  "d": 17,
  "t": 3
};

// Create items array
var items = Object.keys(dict).map(function(key) {
  return [key, dict[key]];
});

// Sort the array based on the second element
items.sort(function(first, second) {
  return second[1] - first[1];
});

// Create a new array with only the first 5 items
console.log(items.slice(0, 5));

第一步是创建项目数组,与Python类似。
items = map(lambda x: [x, var[x]], var.keys())

这可以方便地表示为

items = list(dict.items())

排序步骤类似于Python的排序,使用cmp参数。

items.sort(cmp=lambda x, y: y[1] - x[1])

最后一步类似于Python的切片操作。
print items[:5]
// [['d', 17], ['c', 11], ['z', 9], ['b', 7], ['y', 6]]

1
在 Python 中显示版本让我感到困惑,我希望你只显示 JavaScript 的版本。 - labyrinth

11

@thefourtheye提供的答案在某种程度上是有效的,但它并没有返回相同的“字典”结构。

如果您想要返回具有与原始结构相同的排序对象,则可以对从接受的答案返回的项运行此操作:

sorted_obj={}
$.each(items, function(k, v) {
    use_key = v[0]
    use_value = v[1]
    sorted_obj[use_key] = use_value
})

将它们结合起来,形成一个单一的函数,可以对JavaScript对象进行排序

function sort_object(obj) {
    items = Object.keys(obj).map(function(key) {
        return [key, obj[key]];
    });
    items.sort(function(first, second) {
        return second[1] - first[1];
    });
    sorted_obj={}
    $.each(items, function(k, v) {
        use_key = v[0]
        use_value = v[1]
        sorted_obj[use_key] = use_value
    })
    return(sorted_obj)
} 

示例:

只需将您的对象传递给sort_object函数即可:

dict = {
  "x" : 1,
  "y" : 6,
  "z" : 9,
  "a" : 5,
  "b" : 7,
  "c" : 11,
  "d" : 17,
  "t" : 3
};

sort_object(dict)

结果:

{
"d":17,
"c":11,
"z":9,
"b":7,
"y":6,
"a":5,
"t":3,
"x":1
}

"证明":

res = sort_object(dict)

$.each(res, function(elem, index) {
    alert(elem)
})

2
但是...按照定义,遍历字典不是无序的吗?我的意思是,如果我打印出那个字典,它会以随机顺序排列。 - john k
2
@johnktejik 在答案中可以看到“证明”...它将可重复循环新顺序。从技术上讲,你是正确的,在JavaScript中,“字典”类型对象不应该被信任,但如果在调用sort_object后立即使用新排序的对象,则可以使用它。因此,从技术上讲,Rayjax是正确的,使用对象数组可以保证顺序,但是可能存在快速对对象进行排序的用例,就像我展示的那样。 - Cybernetic
3
干得好!顺便说一句,在不同版本的JS引擎中,使用items.forEach( function(v) { ... })而不是$.each(items, function(k, v) { ... })可以获得更好的兼容性。 - Mostafa Nazari

6

首先,你可能称为“字典”的东西在JavaScript中被称为“对象”。你的“dict”变量就是一个对象。

在JS中,对象是无序的,因此无法对对象进行排序。幸运的是,数组是有序的;我们将把你的字典转换为数组。请看下面的例子。

//dict -> a js object
var dict = {"x" : 1,
        "y" : 6,
        "z" : 9,
        "a" : 5,
        "b" : 7,
        "c" : 11,
        "d" : 17,
        "t" : 3};

//Use the 'keys' function from the Object class to get the keys of your dictionary
//'keys' will be an array containing ["x", "y", "z"...]
var keys = Object.keys(dict);

//Get the number of keys - easy using the array 'length' property
var i, len = keys.length; 

//Sort the keys. We can use the sort() method because 'keys' is an array
keys.sort(); 

//This array will hold your key/value pairs in an ordered way
//it will be an array of objects
var sortedDict = [];

//Now let's go throught your keys in the sorted order
for (i = 0; i < len; i++)
{
    //get the current key
    k = keys[i];

    //show you the key and the value (retrieved by accessing dict with current key)
    alert(k + ':' + dict[k]);

    //Using the array 'push' method, we add an object at the end of the result array
    //It will hold the key/value pair
    sortedDict.push({'key': k, 'value':dict[k]});
}

//Result
console.log(sortedDict);

您可以在此处尝试这里

如果您想更改排序方式,请查看这里

如果您想要前五个最大值,那么,请使用for循环遍历sortedDict 5次,并取出这些值:

function getFiveFirstValues(){
    var valuesArray = [];
    for (i = 0; i < 5; i++)
    {
        valuesArray.push(sortedDict[i].value);
    }
    return valuesArray;
}

请记住,在JavaScript中,对象是无序的。它们可能看起来有序,但实际上并不是这样,并且根据您的浏览器的JS实现,它们的顺序可能会不同。
在此示例中,sortedDict是一个数组(有序),因此可以进行排序。在该数组的每个元素中,您将为您“字典”的每一对找到一个KEY和VALUE对。

5
你可以尝试以下代码,它按数值获取已排序的整数数组。 jsFiddle链接
 function sortJsObject() {
    var dict = {"x" : 1, "y" : 6,  "z" : 9, "a" : 5, "b" : 7, "c" : 11, "d" : 17, "t" : 3};

    var keys = [];
    for(var key in dict) { 
       keys[keys.length] = key;
     }

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

     var sortedValues = values.sort(sortNumber);
     console.log(sortedValues);
}

// this is needed to sort values as integers
function sortNumber(a,b) {
   return a - b;
}

希望这有所帮助。

2
如何通过这个排序值获取字典? - Saurabh Sashank
@SaurabhSashank 只需要返回它吗?像 return sortedValues 这样的吗? - Jiří

2
该函数接受一个字典,或者在JavaScript中更常被称为对象,并返回按照该对象值排序的列表。
function sortObj(obj) {
    // Sort object as list based on values
    return Object.keys(obj).map(k => ([k, obj[k]])).sort((a, b) => (b[1] - a[1]))
}

它与@thefourtheye的答案相同,但更加简洁。


2

严格来说,你不能对“字典”(JavaScript对象)进行排序,因为JavaScript对象没有顺序。它们只是一组键/值对的“袋子”。

如果您想在对象中查找前n个最大值,则需要以某种方式将对象转换为已排序的数组,其元素已经排序,例如使用@thefourtheye的解决方案。如果您想对键进行排序,那么可以使用Object.keys(object).sort()进行排序,正如另一个答案所示。


2

这是一段完整的代码,根据之前的回答和JavaScript中如何迭代(键、值)?

class DictUtils {
    static entries(dictionary) {

        try {

            //ECMAScript 2017 and higher, better performance if support
            return Object.entries(dictionary);

        } catch (error) {

            //ECMAScript 5 and higher, full compatible but lower performance
            return Object.keys(dictionary).map(function(key) {
                return [key, dictionary[key]];
            });
        }

    }
    
    static sort(dictionary, sort_function) {
        return DictUtils.entries(dictionary)
            .sort(sort_function)
            .reduce((sorted, kv)=>{
                sorted[kv[0]] = kv[1]; 
                return sorted;
            }, {});
    }

} 

class SortFunctions {
    static compare(o0, o1) {
        //TODO compelte for not-number values
        return o0 - o1;
    }
    static byValueDescending(kv0, kv1) {
        return SortFunctions.compare(kv1[1], kv0[1]);
    }
    static byValueAscending(kv0, kv1) {
        return SortFunctions.compare(kv0[1], kv1[1]);
    }

}

let dict = {
    "jack": 10,
    "joe": 20,
    "nick": 8,
    "sare": 12
}

let sorted = DictUtils.sort(dict, SortFunctions.byValueDescending)

console.log(sorted);


1

我来跟进一下:

const k = 5;
const dict = {
  "x" : 1,
  "y" : 6,
  "z" : 9,
  "a" : 5,
  "b" : 7,
  "c" : 11,
  "d" : 17,
  "t" : 3
};

const compare = (a, b) => {
    if(a > b) return -1;
    if(a < b) return 1;
    return 0
};

// Object.entries() to convert the dict to: [["x",3],["y",1],["z",2]]
let arr = Object.entries(dict).sort((a, b) => compare(a[1], b[1]));

// Getting the first k = 5 biggest elements:
let biggestElemsArr = [];
for(let j = 0; j < k; j++) {
    biggestElemsArr.push(arr[j][0]);
}

console.log(biggestElemsArr);


0
const sortObjectByValues = (dict: { [key: string]: number }, direction: 'asc'| 'desc' = 'asc') => {
  return Object.fromEntries(Object.entries(dict).sort((a, b) => {
    if (direction === 'asc') {
      return a[1] - b[1]
    }
    return b[1] - a[1]
  }))
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接