问题
I am having a hell of a time finding an answer to this one.
I would like to have a hash in JavaScript, like so:
const hash = {
a: 'A',
c: 'C',
b: 'B'
}
and I would like to sort the object by the value, such that it might become:
const hash = {
a: 'A',
b: 'B',
c: 'C',
}
now, I realize that POJSOs don't guarantee the order of their keys, so I was thinking of using immutableJS
or some object that will guarantee the order of the keys in the hash.
so I am looking for something like:
var newHash = Immutable.Map(hash).sortBy(function(key,val){
return val;
});
But I don't believe this exists. is this too much to ask? How can I find this functionality?
回答1:
now, I realize that POJSOs don't guarantee the order of their keys
They do now, as of ES2015. You still can't access that order via for-in
or Object.keys
, but you can via Object.getOwnPropertyNames. The order is given by the specification operation [[OwnPropertyKeys]]. Ignoring inherited properties, it's basically: Keys that are strings that qualify as integer indexes, in numeric order; followed by remaining keys that are strings, in the order the properties were created; followed by keys that are Symbol
s, in the order they were created.
With that information, if your keys are all strings that don't qualify as integer indexes, then on an ES2015-compliant engine, we can do this:
Start with the properties in any order (e.g.,
a
,c
,b
)Use
Object.keys
to get those keys as an arrayUse
Array#map
to create an array of objects with properties for the key and value (I've usedk
andv
below)Sort the array by value
Use
Array#reduce
to create a new object, adding the properties to it in the sorted order. (Some, including myself, may argue that this is a slight misuse ofreduce
, because the accumulator never actually changes, but hey, it lets us be all l33t [is that still a thing?] and avoid an intermediate variable. Um, because that's a goal? :-) )
The end result is an object with the properties in order of creation, which is the order of their values because we created them in that order. We can access that order via Object.getOwnPropertyNames
.
// The unsorted data
let data = {
a: 'A',
c: 'C',
b: 'B'
};
// Create it sorted
const hash = Object.keys(data)
.map(key => ({k: key, v: data[key]}))
.sort((a, b) => a.v.localeCompare(b.v))
.reduce((o, e) => {
o[e.k] = e.v;
return o;
}, {});
// Display the sorted result
Object.getOwnPropertyNames(hash).forEach(n => {
snippet.log("hash['" + n + "'] = " + hash[n]);
});
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
All of that aside, as I said in a comment on the question, I'm not sure why you'd want to do this. It seems like if we knew what your ultimate goal was, we might be able to point you in a more useful direction...
回答2:
Lodash one-liner:
sorted = _(hash).toPairs().sortBy(1).fromPairs().value();
Live Example:
var data = {a: 'A', c: 'C', b: 'B'};
var hash = _(data).toPairs().sortBy(1).fromPairs().value();
Object.getOwnPropertyNames(hash).forEach(n => {
snippet.log("hash['" + n + "'] = " + hash[n]);
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.6.1/lodash.min.js"></script>
<!-- Script provides the `snippet` object, see http://meta.stackexchange.com/a/242144/134069 -->
<script src="//tjcrowder.github.io/simple-snippets-console/snippet.js"></script>
来源:https://stackoverflow.com/questions/36079323/sort-map-hash-by-values-retaining-keys