I'm trying to sort an object but can't seem to keep the key name of each object after sorting.
Here is the sample json I'm sorting on
series_data: {
embeded: {
objectNameA: {
item: {
last:{reportdate:2014-10-05, trend:=, change:0, value:0},…},
first: {reportdate:2013-01-06, trend:?, change:null, value:0},
high: 1,
low: 0,
median: 0.043478260869565216,
series: [{reportdate:2013-01-06, trend:?, change:null, value:0},…]
},
objectNameB: {…}
I need the objectName becasue it's used in my templates to describe everything else.
here is how I am sorting the data
var items = _.sortBy(series_data.embeded, function(series, index) {
return series.cd.last.value
}).reverse();`
This returns 0:{…}, 1:{…}, 2:{…}, when I need it to be objectNameA:{…},objectNameB:{…}.
OR better yet
0:{objectNameA:{…},…}, 1:{objectNameB:{…},…}
How do I keep or add the objectName while sorting in order from highest to lowest?
I don't think that you can do this with a single call to _.sortBy().
However, you can accomplish it in two steps:
call _.sortBy() and assign the key of each object as a property
call _.each() on the sorted array to get the desired object structure
Here is an example JSBIN
The underlying problem is that objects are unordered collections of properties.
I achieved this by setting a key property on each object within the _.sortBy() - not ideal but one solution
_.sortBy(object, function(item, key) {
item.key = key;
return item.sortattribute;
});
Related
I'm trying to display the values of all key-value pairs in an array of objects. I've tried several methods, for example http://jsfiddle.net/4Mrkp/, but I can't seem to get it to work on my data.
The data, I want to display the car makes only:
{
"response":{
"status":"200",
"messages":{},
"milliseconds":"2"
},
"input":{
"provinceid":{},
"supplierid":"12345678",
"statusid":{ }
},
"output":{
"count":"7",
"list":{
"make":[
{"name":"Alfa Romeo"},
{"name":"Audi"},
{"name":"BMW"},
{"name":"Chevrolet"},
{"name":"Chrysler"},
{"name":"Citroen"},
{"name":"Dacia"}
]
}}
}
My code so far, this displays the word make:
function display_makes(obj)
{
document.getElementById("temp-id").innerHTML =
Object.keys(obj.output.list.make).forEach(function(key){
document.write(key);});
}
So next step is to fetch the values of each element of make, but how? Any thoughts?
Don't use Object.keys on obj.output.list.make because it's an array, use:
obj.output.list.make.forEach(function(obj) {
console.log(obj.name);
});
You may use underscoreJS for manipulating the JSON.
var make = _.map(json_object.output.list.make,function(make) {
document.write(make.name);
return make;
})
This make variable will contain values in key-value pair.
It is easier than you think. Just iterate over the array and forget about the rest:
object.output.list.make.forEach(function(item){
document.write(item);
});
You are working with the array therefore you do not need at all the Object.keys()
I got the following object array:
var arr = [{
2: {
1: { name: "test" },
2: { name: "apple" }
},
3: {
1: { name: "banana" },
2: { name: "pear" }
}
}];
Just some sample data. Now, I got 3 textareas:
<textarea id="first"></textarea>
<textarea id="second"></textarea>
<textarea id="third"></textarea>
And I have the following custom-made function:
function sort(alt)
{
arr.sort(function (a,b)
{
console.log(a);
if (a[2].name < a[2].name)
return (alt) ? 1 : -1;
if (a[2].name > a[2].name)
return (alt) ? -1 : 1;
return 0;
});
}
It should sort the array of objects by name, ascending or descending according to parameter. Now, I got 2 problems. This way I append all the values to the textareas:
for (var key in arr[0])
{
var obj = arr[0][key];
$(ID).append(obj[2].name + '\n');
}
The first time, that code will be executed without running sort. The second time, sort will be executed with false as parameter, than that code will be executed. The third time sort will be executed with true as parameter, than that code will be executed. However, the output of all textboxes is exactly the same.
This is a link to the jsfiddle:
http://jsfiddle.net/JoshB1997/gow4vzsc/
Also, the console.log(a) doesn't get printed in the console.
So variable arr is an array but as far as I can see it contains only one object.
You're trying to sort directly onto the array, since it only has one object it will simply never sort because there is nothing to sort.
You'll want to access arr[0] which is the object containing the actual objects you want to sort however the Object prototype doesn't contain any of the array functions so you cannot call sort on it even tho technically an Array is an Object an Array inherits from Object and not the other way around so the methods from Object are available to Array but not the other way around.
Also, you're trying to compare the same a[2].name with itself so it'll always be false since it's equal, not > or <.
In your case I extract all the name properties from every nested object you have like this (considering the usage of the original arr):
var compare = [];
var alt = false;
for (k in arr[0]) {
if (arr[0].hasOwnProperty(k)) {
for (l in arr[0][k])
if (arr[0][k].hasOwnProperty(l))
compare.push(arr[0][k][l].name);
compare.sort(function(a, b) {
if (a == b)
return 0;
else if (a < b)
return alt ? 1 : -1
else
return alt ? -1 : 1
});
Now you can use the compare array to output the sorted names correctly.
Also - your construction seems overly complex? It has objects and within them are nested objects but you're only sorting and displaying names, is there any reason this structure has to be maintained?
If not I would highly recommend you simplify this to just be an array of names, the loop I made above is far from beautiful and I'd rather have you not use it since it assumes that the outmost object is an object filled with other objects that all have the name property. This code could still break without an extra arr[0][k][l].hasOwnProperty('name').
Either way, the compare array simply contains all the names and it easily sortable with the default sort if you don't make things to complex for yourself.
I suggest you to use http://underscorejs.org/ that contains quite really useful function to transform from object to arrays.
For example in this case you can use something like http://underscorejs.org/#values
let values = _.values(arr[0]);
Now values is an array that contains your two object (2,3) in the form
values = [
{
1: {
name: "test"
},
2: {
name: "apple"
}
},
{
1: {
name: "banana"
},
2: {
name: "pear"
}
}
]
and here you can call your sort function
There is my demo on your code with underscore.js http://jsfiddle.net/gow4vzsc/3/
EDIT: If you cant/wont to include an entire library you can write your code for get the values:
values = [];
for(key in arr[0]){
values.push(arr[0][key]);
}
Here a demo without underscore.js http://jsfiddle.net/3L7ttu2r/1/
I've looked through several posts with similar with issues but I couldn't find one which solves my problem. The others all seemed to be sorting using another array of the same size or by value.
I have two arrays which look like this:
var allCategories = ['Campus', 'Building', 'Floor', 'Room', 'Lecture Theatre', 'Lab'];
var currentCategories = ['Room', 'Lab', 'Campus'];
How can I sort currentCategories so that the order matches that of allCategories?
Desired output:
currentCategories --> ['Campus', 'Room', 'Lab'];
"Sort this array by the indices of its elements in that array":
currentCategories.sort(function(a, b) {
return allCategories.indexOf(a) - allCategories.indexOf(b);
});
// => ["Campus", "Room", "Lab"]
If all that you want is the order of allCategories with the members of currentCategories, you can do the following.
allCategories.filter(function(x){return currentCategories.indexOf(x) != -1})
This assumes that you are treating each array as a set of non-repeating elements. As mentioned in the comments, this method may drop duplicate elements from the final value, or not order duplicate elements in the way you might intend.
The Array.Sort method can be supplied a custom function. You could do something like this:
currentCategories.sort(function(a, b) {
var i = allCategories.indexOf(a),
j = allCategories.indexOf(b);
return i - j;
});
I haven't checked the behaviour for when there are values in currentCategories that are not in allCategories. But then, it wouldn't be living up to its name if that were the case.
If this is a common case, you could generalise it along the following lines:
function sortByList(list) {
return function (a, b) { return list.indexOf(a) - list.indexOf(b); };
}
And call it thusly:
currentCategories.sort(sortByList(allCategories));
How can I do something like the following in JS? I would like to imitate .pop() on an object rather than an array.
var deck = {
'cardK' :'13',
'cardQ' :'12',
'cardAJ':'11'
};
var val = deck.pop();
console.log("Key" + val.key );
console.log("Value" + val.val );
It seems like it's not possible.
.pop is only available on an array. In JavaScript, objects (which are essentially associative arrays) are not ordered like an array, so there is no .pop method.
You could use an array:
var deck = [
{ key: 'cardK', val: 13 },
{ key: 'cardQ', val: 12 },
{ key: 'cardAJ', val: 11 },
];
var val = deck.pop();
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
As suggested by other answers, the best solution here might be to use an array of objects. However you could also create your own pop function that removes a key from an object, for example:
function pop(obj) {
var key = Object.keys(obj).pop();
var result = {key: key, val: obj[key]};
delete obj[key];
return result;
}
var val = pop(deck);
You could add a similar pop function to Object.prototype so that you could do deck.pop(), but I would strongly recommend against that type of design.
You are right, it's not possible. See objects as maps or hash tables, rather than "associative arrays". The properties don't have an order and thus a method such as .pop would not make sense (unless of course it would remove a random property, like Python's dictionaries).
If you want to to use .pop and val.key and val.val, you have to create an array of objects instead:
var deck = [
{key: 'cardK', val: '13'},
{key: 'cardQ', val: '12'},
{key: 'cardAJ', val: '11'}
];
As I'm sure you know, .pop is a prototypal Array method, so you can't use it with Javascript objects.
Calling .pop on an array will remove the last element from the array. However, there isn't a "last" key-value pair with objects, as their order is not ever guaranteed. Despite this, if you don't care about order, you could implement a .pop-like function for use with objects, though, again, it wouldn't remove and return the final key-value pair.
Something like this should do the trick:
function pop(obj) {
for (var key in obj) {
var val = obj[key];
delete obj[key];
return {
'key' : key,
'val' : val,
};
};
};
Combined with your code:
var val = pop(deck);
console.log('key: ' + val.key);
console.log('aa: ' + val.val);
When working with this structure, which can be thought of as an associative array, you need to use different techniques. Things like pop(), slice() and even .length will not work as they do with numeric keyed arrays.
I use string keyed object arrays when searching for the key/value pair needs to happen fast.
Here's a jsPef I just created which shows the benefit of your array structure:
http://jsperf.com/bmcgin-object-array-tests (keep in mind the performance goes way up as the array gets bigger)
Also keep in mind the value can be a number, a string, an array, a function, an object ect...
I have a JSON object like the following:
{"Data": {
"290": {
...
}
"300": {
...
}
"281": {
...
}
}
}
How would I sort this JSON based on the top container keys (i.e. "290", "300", "281")?
Edit: So I used
$.getJSON('current/csf.txt', function(data) { arr = data["Data"]; }
And it sorted them based on the key. Why did this happen?
You've tagged this "JavaScript" so I assume you mean "A JavaScript object generated from this JSON".
In which case:
Loop over the property names (with a for in loop).
Use them to populate an array.
Sort the array.
Use the array as a map.
(You can't store ordered data in an object).
If you want to store the results in JSON, then you will need to change your data structure (and use an array (of objects)). Objects are explicitly unordered.
Your structure is wrong, it should be something like:
{
"Data": [
{
"id": "290"
},
{
"id": "300"
},
{
"id": "282"
}
]
}
Objects are for unordered data. Use arrays for ordered data. And the array is really easy to sort here:
obj.Data.sort(function(a,b){
return a.id - b.id;
});
You can convert to this structure like so:
function copyProps(dest, src) {
for (var key in src) {
dest[key] = src[key];
}
return dest;
}
var newData = [];
for (var key in obj.Data) {
newData.push(copyProps({
id: key
}, obj.Data[key]));
}
I agree with Amberlamps comment, you shouldn't be trying to sort the keys of an object, but if you wanted to for some reason you might take a look at underscore.js's sortBy method
Even if you COULD sort object attributes, there's no guarantee that you could read them back in sorted order. In Javascript, object attributes are not stored in a specific order; an object simply has attributes.
You cannot use array index notation to access object attributes, so the notion of sorting object attributes by key is moot.