Transform array of objects in Jacascript [duplicate] - javascript

I've been looking for a while and want a way to sort a Javascript object like this:
{
method: 'artist.getInfo',
artist: 'Green Day',
format: 'json',
api_key: 'fa3af76b9396d0091c9c41ebe3c63716'
}
and sort is alphabetically by name to get:
{
api_key: 'fa3af76b9396d0091c9c41ebe3c63716',
artist: 'Green Day',
format: 'json',
method: 'artist.getInfo'
}
I can't find any code that will do this. Can anyone give me some help?

UPDATE from the comments:
This answer is outdated. In ES6 objects keys are now ordered. See this question for an up-to-date answer
By definition, the order of keys in an object is undefined, so you probably won't be able to do that in a way that is future-proof. Instead, you should think about sorting these keys when the object is actually being displayed to the user. Whatever sort order it uses internally doesn't really matter anyway.
By convention, most browsers will retain the order of keys in an object in the order that they were added. So, you could do this, but don't expect it to always work:
function sortObject(o) {
var sorted = {},
key, a = [];
for (key in o) {
if (o.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = o[a[key]];
}
return sorted;
}

this function takes an object and returns a sorted array of arrays of the form [key,value]
function (o) {
var a = [],i;
for(i in o){
if(o.hasOwnProperty(i)){
a.push([i,o[i]]);
}
}
a.sort(function(a,b){ return a[0]>b[0]?1:-1; })
return a;
}
The object data structure does not have a well defined order. In mathematical terms, the collection of keys in an object are an Unordered Set, and should be treated as such.
If you want to define order, you SHOULD use an array, because an array having an order is an assumption you can rely on. An object having some kind of order is something that is left to the whims of the implementation.

Just use sorted stringify() when you need to compare or hash the results.

// if ya need old browser support
Object.keys = Object.keys || function(o) {
var result = [];
for(var name in o) {
if (o.hasOwnProperty(name))
result.push(name);
}
return result;
};
var o = {c: 3, a: 1, b: 2};
var n = sortem(o);
function sortem(old){
var newo = {}; Object.keys(old).sort().forEach(function(k) {new[k]=old[k]});
return newo;
}
// deep
function sortem(old){
var newo = {}; Object.keys(old).sort().forEach(function(k){ newo[k]=sortem(old[k]) });
return newo;
}
sortem({b:{b:1,a:2},a:{b:1,a:2}})

Here is a one-liner for you.
Array.prototype.reduce()
let data = {
method: 'artist.getInfo',
artist: 'Green Day',
format: 'json',
api_key: 'fa3af76b9396d0091c9c41ebe3c63716'
};
let sorted = Object.keys(data).sort().reduce( (acc, currValue) => {
acc[currValue] = data[currValue];
return acc;
}, {});
console.log(sorted);
Good luck!!

ES5 Compatible:
function sortByKey(obj) {
var keys = Object.keys(obj);
keys.sort();
var sorted = {};
for (var i = 0; i < keys.length; i++) {
var key = keys[i];
sorted[key] = obj[key];
}
return sorted;
}

This should be used with caution as your code shouldn't rely on Object properties order. If it's just a matter of presentation (or just for the fun !), you can sort properties deeply like this :
function sortObject(src) {
var out;
if (typeof src === 'object' && Object.keys(src).length > 0) {
out = {};
Object.keys(src).sort().forEach(function (key) {
out[key] = sortObject(src[key]);
});
return out;
}
return src;
}

Related

Returning only certain properties from an array of objects in Javascript [duplicate]

This question already has answers here:
From an array of objects, extract value of a property as array
(24 answers)
Closed 8 years ago.
If I have an object such that
var object = function(key,text)
{
this.key = key;
this.text = text;
}
And create an array of these objects
var objArray = [];
objArray[0] = new object('key1','blank');
objArray[1] = new object('key2','exampletext');
objArray[2] = new object('key3','moretext');
is there a way that I can retrieve only one of the properties of all of the objects in the array? For example:
var keyArray = objArray["key"];
The above example doesn't return set keyArray to anything, but I was hoping it would be set to something like this:
keyArray = [
'key1',
'key2',
'key3']
Does anyone know of a way to do this without iterating through the objArray and manually copying each key property to the key array?
This is easily done with the Array.prototype.map() function:
var keyArray = objArray.map(function(item) { return item["key"]; });
If you are going to do this often, you could write a function that abstracts away the map:
function pluck(array, key) {
return array.map(function(item) { return item[key]; });
}
In fact, the Underscore library has a built-in function called pluck that does exactly that.
var object = function(key,text) {
this.key = key;
this.text = text;
}
var objArray = [];
objArray[0] = new object('key1','blank');
objArray[1] = new object('key2','exampletext');
objArray[2] = new object('key3','moretext');
var keys = objArray.map(function(o,i) {
return o.key;
});
console.log(keys); // ["key1", "key2", "key3"]
JS Bin Example
http://jsbin.com/vamey/1/edit
Note that older browsers may not support map but you can easily do this with a for loop:
var keys = [];
for (var i = 0; i < objArray.length; i++) {
keys.push(objArray[i].key);
}
JS Bin Example
http://jsbin.com/redis/1/edit
You would want to do something like this:
objArray.map(function (obj) { return obj.key; });
Here is a JSFiddle to demo: http://jsfiddle.net/Q7Cb3/
If you need older browser support, you can use your own method:
JSFiddle demo: http://jsfiddle.net/Q7Cb3/1/
function map (arr, func) {
var i = arr.length;
arr = arr.slice();
while (i--) arr[i] = func(arr[i]);
return arr;
}
Well something has to iterate through the elements of the array. You can use .map() to make it look nice:
var keys = objArray.map(function(o) { return o.key; });
You could make a function to generate a function to retrieve a particular key:
function plucker(prop) {
return function(o) {
return o[prop];
};
}
Then:
var keys = objArray.map(plucker("key"));
Really "objArray" is an array that have 3 objects inside, if you want list of keys, you can try this:
var keys = [];
for(a in objArray) {
keys.push(objArray[a].key);
}
You have in var keys, the three keys.
Hope that helps! :)

Getting all the values for a given key, in an array of objects, using JavaScript and/or D3.js

I'm building a dashboard that uses D3.js for charts. I have a large array of objects. Each object has 32 key value pairs, with the same keys. Doesn't anyone know a good way to get all the values for a given key?
EDIT:
As soon as I asked the question a simple function came to me. Also thought maybe a function already existed that I wasn't finding.
function getValues(data, key){
var values = [];
data.forEach(function(d){
var v = d[key];
if(!d3.set(values).has(v)){
values.push(v);
}
})
return values;
}
If you're already using d3, take a look at Mike Bostock's "Underscore Equivalents" gist: https://gist.github.com/mbostock/3934356
So
data.map(function(d) { return d[key]; });
will get you all the values. If you only want unique values, use
d3.set(data.map(function(d) { return d[key]; })).values());
I have to create a lot of dashboards using D3 as well. Another option for you which I utilize a lot is underscore.js. It saves me time, and for my needs helps condense code. There is a function called 'pluck' in underscore, which does exactly what you asked for. For an array of objects, you can declare a key and it will return all values.
Example:
var data = [{name: 'dan', value: 40}, {name: 'ryan', value: 50}];
var getKeys = _.pluck(data, 'name');
=> ["dan", "ryan"]
http://underscorejs.org/#pluck
Use d3.keys():
d3.keys(data).filter(function(key) { return key })
Assuming you mean values as simple primitive values -
You can use this altered code of myne (which was originally used to flatten object actually) - to find all the values for specific key (recursive) :
Example : for a very complex object , let's find all the values for a given key named "a"
var data ={a:5,g: [{"a":1,"b":[4,5,6,{a:55},[33, new Date()]]},{"c":2},{"a":3}]};
var g=[];
if (!Object.keys) { //not all browsers support it
Object.keys = function (obj) {
var keys = [],
k;
for (k in obj) {
if (Object.prototype.hasOwnProperty.call(obj, k)) {
keys.push(k);
}
}
return keys;
};
}
function actualType(o)
{
return Object.prototype.toString.apply(o);
}
var arr=actualType([]);
var obj=actualType({});
function work(a, val)
{
if (actualType(a) == obj || actualType(a) == arr)
{
for (var j = 0; j < Object.keys(a).length; j++)
{
if (Object.keys(a)[j] == val) g.push(a[Object.keys(a)[j]]);
else
work(a[Object.keys(a)[j]], val);
}
}
}
work(data,'a') //'a' is the value we're searching
console.log(g) //[5, 1, 55, 3]
http://jsbin.com/yofafove/1/edit

In Javascript, how can I Rename/Renumber a set of properties?

This is one of those questions I'm ashamed to even ask, but I'm working with an external JSON source and I'm forced to do something ugly. So here goes...
I have 'dirty' Javascript object, with property names containing a number at their end:
{ "Friend1" : "Bob",
"Friend6" : "Fred",
"Friend632" : "Gonzo",
"FriendFinder1" : "Dolly",
"FriendFinder4294" : "Jan"
}
I'm trying to figure out a way to clean-up/"zero-index" these property names so the object would look like:
{ "Friend0" : "Bob",
"Friend1" : "Fred",
"Friend2" : "Gonzo",
"FriendFinder0" : "Dolly",
"FriendFinder1" : "Jan"
}
I'm referencing this indexOf/Regex code:
Is there a version of JavaScript's String.indexOf() that allows for regular expressions?
Any strategies you could recommend for doing this? I'll post where I'm at in a bit. Many thanks!
Take the "base" of a key and append items with a common base to an array using the original index. (This produces a sparse array.) Then stretch it out again by enumerating each item with a common base into a new key with 'base'+enumeratedindex.
The trick here is to use a method like forEach to enumerate the array--this will only visit assigned items in a sparse array, allowing you to determine the sort order just by using the original index-part of the key.
If you don't have access to forEach, you can accomplish a similar task by including the key in the array items. Instead of an intermediate array like this:
{Friend: [undefined, "Bob", undefined, undefined, undefined, undefined, "Fred"]}
You have one like this:
{Friend: [[6, 'Fred'],[1, 'Bob']]}
Then you sort the array and visit each item in a foreach loop, extracting the second item.
Here is code:
function rekey(obj) {
var rekey = /^(.*?)(\d+)$/;
var nestedobj = {}, newobj = {};
var key, basekeyrv, newkey, oldidx, newidx;
function basekey(key) {
return rekey.exec(key).splice(1);
}
for (key in obj) {
if (obj.hasOwnProperty(key)) {
basekeyrv = basekey(key);
newkey = basekeyrv[0];
oldidx = parseInt(basekeyrv[1], 10);
if (!nestedobj[newkey]) {
nestedobj[newkey] = [];
}
nestedobj[newkey][oldidx] = obj[key];
}
}
for (key in nestedobj) {
if (nestedobj.hasOwnProperty(key)) {
newidx = 0;
nestedobj[key].forEach(function(item){
newobj[key+newidx++] = item;
});
}
}
return newobj;
}
rekey({
"Friend1" : "Bob",
"Friend6" : "Fred",
"Friend632" : "Gonzo",
"FriendFinder1" : "Dolly",
"FriendFinder4294" : "Jan"
});
produces
{Friend0: "Bob",
Friend1: "Fred",
Friend2: "Gonzo",
FriendFinder0: "Dolly",
FriendFinder1: "Jan"}
Alternatively, without using forEach:
function rekey(obj) {
var rekey = /^(.*?)(\d+)$/;
var nestedobj = {}, newobj = {};
var key, basekeyrv, newkey, oldidx, newidx;
function basekey(key) {
return rekey.exec(key).splice(1);
}
for (key in obj) {
if (obj.hasOwnProperty(key)) {
basekeyrv = basekey(key);
newkey = basekeyrv[0];
oldidx = parseInt(basekeyrv[1], 10);
if (!nestedobj[newkey]) {
nestedobj[newkey] = [];
}
nestedobj[newkey].push([oldidx, obj[key]]);
}
}
for (key in nestedobj) {
if (nestedobj.hasOwnProperty(key)) {
nestedobj[key].sort();
for (newidx = 0; newidx < nestedobj[key].length; newidx++) {
newobj[key+newidx] = nestedobj[key][newidx][1];
}
}
}
return newobj;
}
Could you try doing the following:
{
friend: new Array(),
friendFinder: new Array()
}
then you can:
friend.push() - Add to array
var index = friend.indexOf("Bob") - find in array
friend.splice(index, 1) - remove from the array at index the 1 is for the number to remove.

How to sort a JS object of objects?

I have built an object in PHP, used JSON_encode function and send it as a JSON string to my JS script via ajax. Then I convert it back to an object. The problem I am having is that I wanted to keep the object in the order that it was originally created in. Please see this picture of what the object looks like once I get it into JS:
When I created the object, it was sorted by the customer field alphabetically. The customer name starting with A would come first, B second, etc. As you can see, now, the first element of the object as customer starting with S. It looks like somehow it got automatically sorted by the key of the top-level object, which is an integer, so I understand why this happened.
So i want to do is re-sort this object so that all the sub-objects are sorted by the customer field alphabetically. Is this possible? If so, how do I do it?
Thanks!
I've changed Fabricio Matée answer to become more flexible and return the sorted object.
function alphabetical_sort_object_of_objects(data, attr) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop][attr].toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
var result = [];
for (var i=0, l=arr.length; i<l; i++) {
var obj = arr[i];
delete obj.tempSortName;
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop;
}
}
var item = obj[id];
result.push(item);
}
return result;
}
Then just call the function like this
your_object = alphabetical_sort_object_of_objects(your_object, 'attribute_to_sort');
It's probably the difference between a JavaScript Object and a JavaScript Array. Objects are more like hash tables, where the keys aren't sorted in any particular order, whereas Arrays are linear collections of values.
In your back end, make sure you're encoding an array, rather than an object. Check the final encoded JSON, and if your collection of objects is surrounded by {} instead of [], it's being encoded as an object instead of an array.
You may run into a problem since it looks like you're trying to access the objects by an ID number, and that's the index you want those objects to occupy in the final array, which presents another problem, because you probably don't want an array with 40,000 entries when you're only storing a small amount of values.
If you just want to iterate through the objects, you should make sure you're encoding an array instead of an object. If you want to access the objects by specific ID, you'll probably have to sort the objects client-side (i.e. have the object from the JSON response, and then create another array and sort those objects into it, so you can have the sorted objects and still be able to access them by id).
You can find efficient sorting algorithms (or use the one below from ELCas) easily via Google.
Here's a generic iteration function which pushes all objects into an array and sorts them by their customer property in a case-insensitive manner, then iterates over the sorted array:
function iterate(data) {
var arr = [];
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
var obj = {};
obj[prop] = data[prop];
obj.tempSortName = data[prop].customer.toLowerCase();
arr.push(obj);
}
}
arr.sort(function(a, b) {
var at = a.tempSortName,
bt = b.tempSortName;
return at > bt ? 1 : ( at < bt ? -1 : 0 );
});
for (var i = 0, l = arr.length; i < l; i++) {
var obj = arr[i];
delete obj.tempSortName;
console.log(obj);
for (var prop in obj) {
if (obj.hasOwnProperty(prop)) {
var id = prop; //gets the obj "index" (id?)
}
}
console.log(id);
var item = obj[id];
console.log(item.customer);
//do stuff with item
}
}
Fiddle
sortObject(object){
if(typeof object === 'object'){
if(object instanceof Date){
return object;
}
if(object instanceof Array){
return object.map(element => this.sortObject(element));
} else {
return Object.keys(object).sort().reduce((result, key) => {
if(object[key] && object[key] !== null) {
result[key] = this.sortObject(object[key]);
}
return result;
}, {});
}
}
return object;
}

How to transpose object in underscorejs

In JavaScript I am trying to convert an array of objects with similar keys:
[{'a':1,'b':2}, {'a':3,'b':4}, {'a':5,'b':6,'c':7}]
to an object with an array of values for each key:
{'a':[1,3,5], 'b':[2,4,6], 'c':[7]};
using underscore.js 1.4.2.
I have some working code below, but it feels longer and clunkier than just writing nested for loops.
Is there a more elegant way of doing this in underscore? Is there something simple I'm missing?
console.clear();
var input = [{'a':1,'b':2},{'a':3,'b':4},{'a':5,'b':6,'c':7}];
var expected = {'a':[1,3,5], 'b':[2,4,6], 'c':[7]};
// Ok, go
var output = _(input)
.chain()
// Get all object keys
.reduce(function(memo, obj) {
return memo.concat(_.keys(obj));
}, [])
// Get distinct object keys
.uniq()
// Get object key, values
.map(function(key) {
// Combine key value variables to an object
// ([key],[[value,value]]) -> {key: [value,value]}
return _.object(key,[
_(input)
.chain()
// Get this key's values
.pluck(key)
// Filter out undefined
.compact()
.value()
]);
})
// Flatten array of objects to a single object
// [{key1: [value]}, {key2, [values]}] -> {key1: [values], key2: [values]}
.reduce(function(memo, obj) {
return _.extend(memo, obj);
}, {})
.value();
console.log(output);
console.log(expected);
console.log(_.isEqual(output, expected));
Thanks
Sounds like you want zip for objects. This would be the analogous method for objects:
_.transpose = function(array) {
var keys = _.union.apply(_, _.map(array, _.keys)),
result = {};
for (var i=0, l=keys.length; i<l; i++) {
var key = keys[i];
result[key] = _.pluck(array, key);
}
return result;
};
However, I would just use
_.transpose = function(array) {
var result = {};
for (var i=0, l=array.length; i<l)
for (var prop in array[i])
if (prop in result)
result[prop].push(array[i][prop]);
else
result[prop] = [ array[i][prop] ];
return result;
};
without any Underscore at all :-) Of course, you could use some iterator methods, it then might look like
_.reduce(array, function(map, obj) {
return _.reduce(obj, function(map, val, key) {
if (key in map)
map[key].push(val)
else
map[key] = [val];
return map;
}, map);
}, {});
You can use lodash's zipObject mehtod: https://lodash.com/docs#zipObject
You need 3 lines of lodash:
_.merge.apply(null, _.union([{}], myArrayOfObjects, [function (a, b) {
return _.compact(_.flatten([a, b]));
}]))
See the docs of _.merge for more details on what the function does.

Categories

Resources