I’m trying to order an object data structure by the value.
{apple: 1, pear: 85, orange: 24, blueberry: 18}
I want to achieve a reorder by value in DESC order. I don’t think there is a a method to do so, even if this object was wrapped in an Array, but wanted to check.
My other thought process was to separate the key value pair into 2 separate arrays. Then loop the value array, search for the max vale and capture the index at that point and that particular index should match at the key array. Then i can move the key/value pair into a third/separate array keeping order by max value. Then based on the index number captured, pop from both the key and value array.
If there is a better method please feel free to share?
An Object's keys are not sorted, so you will not be able to achieve what you want with just an Object.
If you use an Array, however, you can use Array.sort():
const myArray = [{apple: 1}, {pear: 85}, {orange: 24}, {blueberry: 18}]
myArray.sort((e1, e2) => Object.values(e2)[0] - Object.values(e1)[0])
console.log(myArray)
Related
I have the mapping of abbreviation and full name as follow:
object = {"TSLA":"TESLA INC.","GOOG":"GOOGLE INC.","APPL":"APPLE INC.","AMZN":"AMAZON CORPORATION", "MSFT":"MICROSOFT CORPORATION"}
as an output of function i get the following array:
array = ["AMZN","APPL"]
I want to display the values of the associated keys as follows:
output_array = ["AMAZON CORPORATION", "APPLE INC."]
Note that, the actual object has more key: value pairs
Using IndexOf() I can replace one value. However, I believe there must be a way of mapping the array elements to replace the values at once.
Since I am new to JS, I would appreciate any suggestion.
array.map(abbr => object[abbr]) does the job; it iterates over the array rather than the object, which is more efficient as the object already is a lookup table with the right keys - you are right, there is no need to use indexOf which uses a linear search.
I have a variable with 4 indexes (nt_data). What I need to do it to be able to grab the numbers highlighted in green and add them into another variable or array.
when I try nt_data[0] it'll list all the details including one of the numbers I want to grab (number 11):
and when I try nt_data[0][11] it'll show me the details inside index number 11 (which isn't an index):
what I need to do is to grab all of those numbers (11, 12, 3, 8) and put them into a variable so I can use them dynamically to point to that index. these numbers are randomly generated and change each time.
You are trying to get key from Object, The Object.keys() method returns an array of a given object's own enumerable property names, iterated in the same order that a normal loop would.
Object.keys() returns an array whose elements are strings corresponding to the enumerable properties found directly upon object. The ordering of the properties is the same as that given by looping over the properties of the object manually.
Here's the example of retrieve key from object array:
let nt_data = [
{11: 'a'}, {12: 'b'}, {3: 'c'}, {8: 'd'}
];
for(index in nt_data){ console.log(Object.keys(nt_data[index])[0]) }
I need to create one Object where the keys are strings composed of numbers but I couldn't sort them in the correct way:
let simple_arr = ['00', '11', '22', '33'];
let simple_obj = {};
for (let it of simple_arr) {
simple_obj[it] = "anything";
}
for (let it2 in simple_obj) {
console.log(it2)
}
The output that I would like is: 00, 11, 22, 33.
But it reproduces: 11, 22, 33, 00.
I already tried to sort this object with Object.keys, but always when I set an iterator on it the value "00" goes to the end.
You cannot rely on the output you've said you want using a for-in loop. Although object properties have order as of ES2015, for-in loops don't. (Neither does the array from Object.keys.)
If you want order, you want an array. (But you can use a Map, too, in some situations; see below.)
Moreover, even with ES2015's property order, the keys you've shown will never be in the order you've shown, because '00' is different from '11', '22', and '33': It's not a canonical number String. The ES2015 order (for the operations that support it) is properties whose names are strings in canonical number String format, in order numerically, followed by other string-named properties in the order they were added, followed by Symbol-named properties.
So your object will never behave as you've said you want. Use an array.
(Of course, if you introduce a prefix so none of them is in canonical number String format and add the properties in the order you want them, that would work with Object.getOwnPropertyNames and other operations that support the order. But I really wouldn't do that.)
Another option is to use a Map, which unlike objects always follows the order that the keys were first used.¹ If you create a Map like this:
const map = new Map(simple_arr.map(key => [key, "anything"]));
...then looping through that map will reliably visit the '00' entry, then the '11' entry, then the '22' entry, then the '33' entry:
const simple_arr = ['00', '11', '22', '33'];
const map = new Map(simple_arr.map(key => [key, "anything"]));
for (const [key, value] of map.entries()) {
console.log(key, value);
}
¹ That's the simple version. The longer version: If you add a key/value to the map and that key is not already in the map, it goes at the end of the list of the map's keys. If you set a new value for that key, it doesn't move in that list. If you remove the key and then add it again later, it goes at the end again.
Objects have no concept of ordering when it comes to their keys. Even if you could achieve this with this particular data set in your particular browser, there's no guarantee the keys will come out in the order you want.
If you really want to achieve this, you should sort the keys returned from Object.keys() and iterate over that.
My original answer above is incorrect. As of ES2015, object keys do have a specific order. I still maintain that trying to rely on the order of keys of an object is probably a bad idea - Use a Map to retain the original values of your keys (without them being coerced to a string) and order the keys when iterating, instead.
Since ES2015 object keys do have a traversal order:
Strings that are legitimate numbers (Integer indices) come first, and ordered by their value
Strings that aren't are placed after numeric strings, and their order is defined by the order of entry
Convert 00 to 0 so it will be ordered by the numeric value:
const simple_arr = ['0', '11', '22', '33'];
const simple_obj = {};
for(let it of simple_arr){
simple_obj[it] = "anything";
}
for(let it2 in simple_obj){
console.log(it2)
}
This is a follow up to a previous question I asked:
Sort JSON response by key value
So I know that objects cannot be sorted using the .sort method and if I push each object into an array, I can sort it the way I want.
Why does .sort not work on this:
{ A:{...}, B:{...}, C:{...} }
but works on this:
[ {...}, {...}, {...} ]
It's still accessing and working with object properties in both examples, right?
Here's some code:
var query = {
"736":{
ns: 42,
pageid: 12,
lang: "en",
index: 3
},
"421":{
ns: 12,
pageid: 36,
lang: "en",
index: 4
},
"102":{
ns: 2,
pageid: 19,
lang: "en",
index: 1
}
};
var queryArr = [{ns: 42, pageid: 12, lang: "en", index: 3}, {ns: 12, pageid: 36, lang: "en", index: 4}, {ns: 2, pageid: 19, lang: "en", index: 1}];
query is an object with multiple objects in it, and queryArr is an arry with multiple objects in it. If I wanted to sort query by its index key's value, I'd have to convert it to an arry first, and then run .sort on that array, correct?
What I want to know is why. What prevents query from being sorted, but allows the objects inside queryArr to be sorted? They're both still objects right? The only difference is the outer body is an object in the first, and an array in the second - but it's still working with objects when sorting.
My sort function still referneces the index using the object property accessor:
queryArr.sort(function(i,j){
return j.index - i.index;
});
Array object is object where the positive integer keys are used:
a = [, 1]
a[.1] = .1
a[-1] = -1
console.log( a )
console.log( { ...a } )
If the order of the properties can't be guaranteed, then for example array object [0, 1] can be stored as { "0": 0, "1": 1 } or { "1": 1, "0": 0 }.
Most array looping constructs will look for the "0" property before the "1" property, so the property order doesn't really matter.
Sorting array doesn't change it's properties order, but swaps the values associated with the properties.
Arrays are a special way of sequentially storing data. In the earliest implementations, this would be done by actually storing the array objects sequentially in memory. And resorting would actually physically move the objects in memory. So in your example where you have indices 102, 421, and 736. If you translated this to an array, you would actually have an array of length 737. 0 to 101 would be undefined, then you would have your object at 102. 103 to 420 would be undefined, then object 421. Et cetera.
Good to note that in your example when you translated your object into an array, you lost your keys (102, 421, 736). They simply became (0,1,2). In your example maybe this was okay, but if you had an object with properties like width, height, length, having these replaced with simple array indices like 0,1,2 would be a pretty significant loss of information.
Objects don't work the same way at all. They are not designed to store data sequentially, but hierarchically. So you can have a key 102 that points to an object, but you don't have to have keys 0-101. And key 102 doesn't designate the "order" of the item. It's just a name, and it could just as easily be length or fred or green as 102.
This mirrors reality. For example you might have an array to store a group of people, perhaps starting in order of age. And you could re-sort the list by different properties, like alphabetical by last name, or by height, etc.
But if we look at the objects within that array, it really makes no sense to talk about the order of firstName, lastName, height, weight, age, etc. There isn't really any "order" to speak of: weight doesn't have to come before height, or vice versa. And some people may like to see Last,First, while others prefer First Last. These properties are things we mostly want to be able to access directly by name, so an array isn't really ideal. We want named properties. Hence an object. Don't be confused just because you chose numbers as your property names...they're still names, not indices.
However it is of course possible to iterate all the properties of an object, and it is even possible to control the order in which you iterate them. Traditionally in javascript this iteration was done with the for...in syntax, which goes all the way back to es1. But you couldn't control the order in which the object's keys were iterated. To control order we would have to use for...in to populate an array of keys, then sort the array, then re-loop over the array.
However, it is possible in the newer es6 javascript world to iterate in some great new ways. For example, you can use Object.keys() to get an array of all the object keys (property names), and then you could sort this array. Saves the step of populating an array with for...in.
Another more advanced possibility in es6 (which uses Object.keys) is to actually make the object itself iterable by adding a Symbol.iterator. Again, this only works in es6+.
However the Symbol.iterator gives you a lot of power. This is what it looks like:
query[Symbol.iterator] = function*() {
let properties = Object.keys(this).sort();
for(let p of properties) {
yield {key:p, value:this[p]}
}
}
Once you add this iterator to the object, now you can use things like for...of. And in this example I added a .sort(), so this would iterate over the object's properties in ascending numeric order by key: 102, 421, 736. And since we are yielding an object with key and value, we are still able to see the key value, which we would NOT have if we had just translated to an array.
for(let {key,value} of query) {
console.log(key);
}
I have an array of ints called SelectedItems. I have another array that contains objects that's called AvailableItems and that was parsed from json; these Item objects have the properties {ContainerID, ContainerName, ItemID, ItemName}.
I want to convert SelectedItems from an array of ints to an array of Items where each ItemID is replaced with the Item object that corresponds to the ItemID in AvailableItems. Each ItemID in SelectedItems is unique.
I started with 2 loops: one that loops through each element of SelectedItems but then I find myself looping through AvailableItems each time to find the corresponding ItemID with the object keys I need to copy into SelectedItems.
So basically I built a seemingly very inefficient loop. I was wondering if there was a better way to do it by avoiding a repeated loop inside a loop?
Sample data:
For AvailableItems, you have
{
ContainerID: i,
ContainerName: 'SomeName',
ItemID: j,
ItemName: 'SomeOtherName'
}
with may be 1,000 objects and then SelectedItems is array of ints
[23,43,64,34...]
Thanks.
You could put each object in the numeric array AvailableItems at the index that matches its ItemID.
So you know that the item with an ItemID of 5 is at AvailableItems[5] instead of having to loop through and find it.
Not sure what effect this will have if you have big gaps between different ItemID values, but you can try it and see if it works well.
UPDATE:
After a quick search, and reading this answer, it looks like having gaps between your indexes will not waste a bunch of memory. However, it will affect the result of checking AvailableItems.length. If you have an array with one entry, but the index of that entry is 500, then AvailableItems.length will return 501, even though there is only one entry in the array.
As long as you don't need to use the length function, this solution should work for you.
If you are able to get any arbitrary AvailableItem without looping through the whole array by just addressing it by its ID(if you have an index-based array where IDs are indexes) then you can go through the SelectedItems and check if it exists in AvailableItems, and if it does then you convert the SelecteItem into an object and add it to some temporary array for later use.