ChatGPT解决这个技术问题 Extra ChatGPT

按值对对象属性进行排序

如果我有一个 JavaScript 对象,例如:

var list = {
  "you": 100, 
  "me": 75, 
  "foo": 116, 
  "bar": 15
};

有没有办法根据价值对属性进行排序?所以我最终得到

list = {
  "bar": 15, 
  "me": 75, 
  "you": 100, 
  "foo": 116
};
不仅是“排序”,更重要的是对数字进行排序。数字不受 Javascripts Array.sort() 方法的影响,这意味着您不仅需要找到对属性进行排序的方法,还必须编写自己的函数来比较数值。
在阅读答案之前:答案是否定的。对象属性的顺序在 ECMAScript 中是非标准的。你永远不应该对 JavaScript 对象中元素的顺序做出假设。对象是属性的无序集合。下面的答案向您展示了如何在数组的帮助下“使用”排序的属性,但从不真正改变对象本身的属性顺序。所以,不,这是不可能的。即使您构建具有预排序属性的对象,也不能保证它们将来会以相同的顺序显示。继续阅读:)。
@GovindRai 然而,在现实世界的前端应用程序中,我们循环使用 ID 作为键的对象集合,如果转换为 HTML 模板,顺序很重要。你说他们没有顺序,我说他们完全符合我在控制台中看到的顺序。在当前浏览器中记录它们。该订单可以重新排序。一旦您遍历它们,它们就会有订单。
@GovindRai:现在有一种按规范中指定顺序访问属性的方法。这是个好主意吗?几乎可以肯定不是。 :-) 但它就在那里,从 ES2015 开始。
2019 年访问者:检查这个几乎没有被赞成的基于 Object.entries 的答案,这是自 ES2017 以来最干净、最易读的最新技术:stackoverflow.com/a/37607084/245966

A
Audwin Oyong

将它们移动到一个数组中,对该数组进行排序,然后将该数组用于您的目的。这是一个解决方案:

let maxSpeed = {
    car: 300, 
    bike: 60, 
    motorbike: 200, 
    airplane: 1000,
    helicopter: 400, 
    rocket: 8 * 60 * 60
};
let sortable = [];
for (var vehicle in maxSpeed) {
    sortable.push([vehicle, maxSpeed[vehicle]]);
}

sortable.sort(function(a, b) {
    return a[1] - b[1];
});

// [["bike", 60], ["motorbike", 200], ["car", 300],
// ["helicopter", 400], ["airplane", 1000], ["rocket", 28800]]

一旦你有了数组,你可以按照你喜欢的顺序从数组中重建对象,从而完全实现你的目标。这适用于我所知道的所有浏览器,但它取决于实现的怪癖,并且可能随时中断。你永远不应该对 JavaScript 对象中元素的顺序做出假设。

let objSorted = {}
sortable.forEach(function(item){
    objSorted[item[0]]=item[1]
})

在 ES8 中,您可以使用 Object.entries() 将对象转换为数组:

const maxSpeed = { 汽车:300,自行车:60,摩托车:200,飞机:1000,直升机:400,火箭:8 * 60 * 60 }; const sortable = Object.entries(maxSpeed) .sort(([,a],[,b]) => ab) .reduce((r, [k, v]) => ({ ...r, [k ]: v }), {});控制台.log(可排序);

在 ES10 中,您可以使用 Object.fromEntries() 将数组转换为对象。那么代码可以简化为:

const maxSpeed = { 汽车:300,自行车:60,摩托车:200,飞机:1000,直升机:400,火箭:8 * 60 * 60 }; const sortable = Object.fromEntries(Object.entries(maxSpeed).sort(([,a],[,b]) => ab));控制台.log(可排序);


您能否将“您可以重建”重新表述为“您可以使用数组来维护键的顺序并从对象中提取值”?正如您自己所提到的,它不仅是非标准的,而且如今除了 Chrome 之外,更多的浏览器都打破了这个错误的假设,所以最好不要鼓励用户尝试它。
这是您的代码的更紧凑版本。 Object.keys(maxSpeed).sort(function(a, b) {return -(maxSpeed[a] - maxSpeed[b])});
@TheBrain:补充一点,keys() 仅受 IE9+ (和其他现代浏览器)支持,如果这值得关注的话。此外,keys() 排除了元素原型链中的可枚举属性(与 for..in 不同)——但这通常更可取。
_.pairs 将对象转换为 [ [key1, value1], [key2, value2] ]。然后调用 sort 。然后调用 _.object 将其转回。
我的项目需要对象键才能干净地合并,但还需要显式排序,因为元数据驱动 UI。我遵循了类似的方法,只是我添加了一个 hasOwnProperty 检查以避免爬上原型链。这是一篇关于在 JS 中迭代对象属性的好文章hackernoon.com/…
M
Mohideen bin Mohammed

我们不想复制整个数据结构,或者在需要关联数组的地方使用数组。

这是与 bonna 做同样事情的另一种方法:

var list = {“你”:100,“我”:75,“富”:116,“酒吧”:15}; keysSorted = Object.keys(list).sort(function(a,b){return list[a]-list[b]}) console.log(keysSorted); // bar,me,you,foo


这似乎是按键排序,而不是按值排序,这不是问题所要求的吗?
它按值排序,并显示键——但是当它打印出来时我们会丢失值计数,因为它只打印键。
JavaScript 中不保证对象属性顺序,因此应该对数组进行排序,而不是对象(这就是您所说的“关联数组”)。
不要忘记。 keysSorted 是一个数组!不是对象!
如果将 .map(key => list[key]); 添加到排序的末尾,它将返回整个对象,而不仅仅是键
i
inorganik

您的对象可以具有任意数量的属性,如果您将对象放入数组中,您可以选择按您想要的任何对象属性(数字或字符串)进行排序。考虑这个数组:

var arrayOfObjects = [   
    {
        name: 'Diana',
        born: 1373925600000, // Mon, Jul 15 2013
        num: 4,
        sex: 'female'
    },
    {

        name: 'Beyonce',
        born: 1366832953000, // Wed, Apr 24 2013
        num: 2,
        sex: 'female'
    },
    {            
        name: 'Albert',
        born: 1370288700000, // Mon, Jun 3 2013
        num: 3,
        sex: 'male'
    },    
    {
        name: 'Doris',
        born: 1354412087000, // Sat, Dec 1 2012
        num: 1,
        sex: 'female'
    }
];

按出生日期排序,从大到小

// use slice() to copy the array and not just make a reference
var byDate = arrayOfObjects.slice(0);
byDate.sort(function(a,b) {
    return a.born - b.born;
});
console.log('by date:');
console.log(byDate);

按名称分类

var byName = arrayOfObjects.slice(0);
byName.sort(function(a,b) {
    var x = a.name.toLowerCase();
    var y = b.name.toLowerCase();
    return x < y ? -1 : x > y ? 1 : 0;
});

console.log('by name:');
console.log(byName);

http://jsfiddle.net/xsM5s/16/


按名称排序不应 substr 出第一个字符;否则 DianaDebra 具有未定义的顺序。此外,您的 byDate 排序实际上使用 num,而不是 born
这看起来不错,但请注意,要比较字符串,您可以使用 x.localeCompare(y)
@JemarJones localCompare 看起来是一个非常有用的功能!请注意,并非所有浏览器都支持它 - IE 10 及更低版本、Safari Mobile 9 及更低版本。
@inorganik 是的,对于那些需要支持这些浏览器的人来说非常好
这是一个对象数组,不是 OP 要求的(具有多个属性的对象)
k
kiding

ECMAScript 2017 引入了 Object.values / Object.entries。顾名思义,前者将一个对象的所有值聚合成一个数组,后者将整个对象聚合成一个[key, value]数组的数组; Python 的 dict.values()dict.items() 等价物。

这些功能使将任何散列排序为有序对象变得非常容易。到目前为止,只有一小部分 JavaScript 平台支持它们,但您可以在 Firefox 47+ 上试用。

编辑:现在受 all modern browsers! 支持

let obj = {"you": 100, "me": 75, "foo": 116, "bar": 15};

let entries = Object.entries(obj);
// [["you",100],["me",75],["foo",116],["bar",15]]

let sorted = entries.sort((a, b) => a[1] - b[1]);
// [["bar",15],["me",75],["you",100],["foo",116]]

这怎么可能回答问题的标题 Sorting JavaScript Object by property value ?您误解了我认为的问题,因为您要更改原始对象而不是从中创建新数组。
@vsync 这个答案给出的结果与接受的答案相同,但代码更少且没有临时变量。
FWIW,这个答案很干净,是唯一帮助我的答案。
只有在 ff 中,不是 ie,也不是 chrome,它们会自动对对象进行排序。 wtf
为了进一步简化,将该过程合并为一行:let sorted = Object.entries(obj).sort((a, b) => a[1] - b[1]);
t
tagurit

为了完整起见,此函数返回对象属性的排序数组:

function sortObject(obj) {
    var arr = [];
    for (var prop in obj) {
        if (obj.hasOwnProperty(prop)) {
            arr.push({
                'key': prop,
                'value': obj[prop]
            });
        }
    }
    arr.sort(function(a, b) { return a.value - b.value; });
    //arr.sort(function(a, b) { a.value.toLowerCase().localeCompare(b.value.toLowerCase()); }); //use this to sort as strings
    return arr; // returns array
}

var list = {"you": 100, "me": 75, "foo": 116, "bar": 15};
var arr = sortObject(list);
console.log(arr); // [{key:"bar", value:15}, {key:"me", value:75}, {key:"you", value:100}, {key:"foo", value:116}]

JSFiddle with the code above is here。此解决方案基于 this article

Updated fiddle for sorting strings is here. 您可以从中删除两个额外的 .toLowerCase() 转换,以进行区分大小写的字符串比较。


对象数组呢? [ {name:Will}, {name:Bill}, {name:Ben}]
您好 Will,您可以使用 localeCompare function 进行此比较。将其添加到上面的答案中。
很好的解决方案。字符串排序需要返回
@Stano 正确而简单的解决方案。非常感谢。
J
Jason J. Nathan

@marcusR 的 answer 的“箭头”版本供参考

var myObj = { you: 100, me: 75, foo: 116, bar: 15 };
keysSorted = Object.keys(myObj).sort((a, b) => myObj[a] - myObj[b]);
alert(keysSorted); // bar,me,you,foo

更新:2017 年 4 月 这将返回上面定义的已排序 myObj 对象。

const myObj = {你:100,我:75,foo:116,bar:15}; const 结果 = Object.keys(myObj) .sort((a, b) => myObj[a] - myObj[b]) .reduce( (_sortedObj, key) => ({ ..._sortedObj, [key]: myObj[key] }), {} ); document.write(JSON.stringify(result));

更新:2021 年 3 月 - 具有排序功能的 Object.entries(根据评论更新)

const myObj = {你:100,我:75,foo:116,bar:15}; const 结果 = Object .entries(myObj) .sort((a, b) => a[1] - b[1]) .reduce((_sortedObj, [k,v]) => ({ ..._sortedObj, [k]: v }), {}) document.write(JSON.stringify(result));


不适用于 var myObj = {"1": {"Value": 40}, "2": {"Value": 10}, "3": {"Value": 30}, "4": {"Value": 20}};
OP的问题以及这个答案不包含嵌套对象@Rohanil也许你想问另一个问题而不是投票。您的各种类型的嵌套对象显然需要比此解决方案提供的更多
请注意:您的更新实际上不会起作用。至少不是无处不在,也不是因为 entries。根据标准,对象是属性的无序集合。好吧,这意味着如果您在按属性值或其他任何内容对新对象进行排序后尝试构造新对象,则属性键顺序再次变为未定义。例如,Chrome 默认对属性键进行排序,因此每次尝试对它们进行不同的排序都是无用的。您唯一的机会是根据您的订购偏好获得“索引”并相应地遍历原始对象。
是的@ZorgoZ,你是对的,很多人在这篇文章中提到了它。大多数时候,我们在转换为另一种类型(如 JSON)或另一个 reduce 函数之前将此函数用作转换。如果目标是此后改变对象,那么可能会出现意想不到的结果。我在跨引擎的这个功能上取得了成功。
注意:您不想在 Object.entries() 上使用 sort()
N
NickFitz

JavaScript 对象根据定义是无序的(请参阅 ECMAScript Language Specification,第 8.6 节)。语言规范甚至不保证,如果您连续两次迭代对象的属性,它们第二次将以相同的顺序出现。

如果您需要订购物品,请使用数组和 Array.prototype.sort 方法。


请注意,关于这一点有很多争论。大多数实现都按照添加元素的顺序保留列表。 IIRC,Chrome 没有。关于 Chrome 是否应该与其他实现保持一致存在争论。我的信念是 JavaScript 对象是一个散列,不应该假设任何顺序。我相信 Python 也经历了同样的争论,并且最近引入了一个新的有序哈希列表。对于大多数浏览器,您可以通过重新创建对象、按排序值添加元素来做您想做的事情。但你不应该。
编辑。 Chrome 通常会保持秩序,但并非总是如此。这是相关的 Chromium 错误:code.google.com/p/chromium/issues/detail?id=883
该错误报告是不合理的,那些依赖未记录行为的人就是那些有错误的人。阅读 ECMASCript 第 8.6 节;它明确指出“一个对象是一个无序的属性集合”。任何人如果在一些实现中发现它似乎并非如此,然后开始依赖于特定于实现的行为,那么他们就犯了一个大错误,他们不应该试图将责任推卸给自己。如果我在 Chrome 团队中,我会将该错误报告标记为“无效,WontFix”。
EcmaScript 5 实际上将枚举顺序定义为插入顺序——没有定义被认为是 ES3 中的规范错误。值得注意的是,EcmaScript 规范定义了没有人认为理智的行为——例如规范行为是在许多情况下在运行时抛出语法错误,根据错误使用 continue、break、++、--、const 等根据规范,在到达该代码之前抛出异常的任何引擎都是错误的
@olliej - 我认为这是不正确的。规范说:“枚举属性的机制和顺序(第一个算法中的步骤 6.a,第二个算法中的步骤 7.a)没有指定”。这是最终草案 PDF 的第 92 页。
A
Alireza

好的,你可能知道,javascript 有 sort() 函数,可以对数组进行排序,但没有对象......

因此,在这种情况下,我们需要以某种方式获取键数组并对它们进行排序,这就是 api 在大多数情况下为您提供数组中的对象的原因,因为 Array 具有比对象字面量更多的本机函数,无论如何,快速独奏使用 Object.key ,它返回一个对象键数组,我在下面创建了 ES6 函数,它为你完成了这项工作,它在 javascript 中使用本机 sort() 和 reduce() 函数:

function sortObject(obj) {
  return Object.keys(obj)
    .sort().reduce((a, v) => {
    a[v] = obj[v];
    return a; }, {});
}

现在你可以像这样使用它:

let myObject = {a: 1, c: 3, e: 5, b: 2, d: 4};
let sortedMyObject = sortObject(myObject);

检查 sortedMyObject ,您可以看到按如下键排序的结果:

{a: 1, b: 2, c: 3, d: 4, e: 5}

同样这样,主对象不会被触及,我们实际上得到了一个新对象。

我还创建了下面的图像,以使功能步骤更加清晰,以防您需要对其进行一些更改以按照自己的方式工作:

https://i.stack.imgur.com/iJ6dX.png


这种按键排序,而不是按值排序。
@ROROROOROROR,这只是说明它是如何工作的,因为它们并没有那么不同,但一切都很好,我也会按值添加排序
按值排序是错误的,它是您的数据集。将 c: 3 更改为 c: 13,您会看到它分崩离析。
@VtoCorleone这只是一个自然的排序错误,1是第一位的,而不是所呈现的算法中的缺陷。
V
Vasil Nikolov
var list = {
    "you": 100, 
    "me": 75, 
    "foo": 116, 
    "bar": 15
};

function sortAssocObject(list) {
    var sortable = [];
    for (var key in list) {
        sortable.push([key, list[key]]);
    }
    // [["you",100],["me",75],["foo",116],["bar",15]]

    sortable.sort(function(a, b) {
        return (a[1] < b[1] ? -1 : (a[1] > b[1] ? 1 : 0));
    });
    // [["bar",15],["me",75],["you",100],["foo",116]]

    var orderedList = {};
    for (var idx in sortable) {
        orderedList[sortable[idx][0]] = sortable[idx][1];
    }

    return orderedList;
}

sortAssocObject(list);

// {bar: 15, me: 75, you: 100, foo: 116}

简单而完美!这回答了这个问题。谢谢。
javascript中不保证键顺序,所以如果键是整数等,这对我来说会失败
确切地说,ParoX。当键是整数类型时,这不能正常工作。
j
julianljk

使用 ES6 更新:如果您担心要迭代一个排序对象(这就是我想您希望对象属性排序的原因),您可以使用 Map 对象。

您可以按排序顺序插入(键、值)对,然后执行 for..of 循环将保证让它们按照您插入的顺序循环

var myMap = new Map();
myMap.set(0, "zero");
myMap.set(1, "one");
for (var [key, value] of myMap) {
  console.log(key + " = " + value);
}
// 0 = zero 
// 1 = one

同样在 ES6 (ES2015) 中:对象属性 do 有顺序(或者有一种方法可以按定义的顺序访问它们,这取决于您的观点)。如果属性名称是字符串并且看起来不像数组索引,则顺序是它们添加到对象的顺序。此顺序指定为由 for-inObject.keys 遵守,但它定义为由 Object.getOwnPropertyNames 和其他用于访问属性的新方法遵守名称数组。所以这是另一种选择。
但是“排序”操作在哪里?它们根本没有排序
@Green 我想我想在这里强调的是,使用 Map 你实际上有一个可以按排序顺序存储的数据结构(对你的数据进行排序,循环遍历它并将其存储在地图中),而你不是保证与对象。
o
orad

非常简短!

var sortedList = {};
Object.keys(list).sort((a,b) => list[a]-list[b]).forEach((key) => {
    sortedList[key] = list[key]; });

d
daniil4udo

对没有多个 for 循环的值进行排序(按键排序,将排序回调中的索引更改为“0”)

常量列表 = {“你”:100,“我”:75,“富”:116,“酒吧”:15 }; let sorted = Object.fromEntries( Object.entries(list).sort( (a,b) => a[1] - b[1] ) ) console.log('Sorted object: ', sorted)


t
tagurit

Underscore.js 或 Lodash.js 用于高级数组或对象排序

var data = { "models": { "LTI": [ "TX" ], "Carado": [ "A", "T", "A(пасс)", "A(груз)", "T(пасс )”、“T(груз)”、“A”、“T”]、“SPARK”:[“SP110C 2”、“sp150r 18”]、“Autobianchi”:[“A112”]}}; var arr = [], obj = {}; for (var i in data.models) { arr.push([i, _.sortBy(data.models[i], function(el) { return el; })]); } arr = _.sortBy(arr, function(el) { return el[0]; }); _.map(arr, function(el) { return obj[el[0]] = el[1]; });控制台.log(obj);