Convert object keys into array list? - javascript

If I have an object like:
var o = {a:1,b:2,c:3};
I want to get:
['a','b','c'];
I want to use for (var i in o) because this will include properties from prototype chain. I could have used Object.keys(o) if I didn't need properties from prototype chain.
I was thinking I could use some of Array.prototype.* methods here. Like map but this is too advance for me.
I can make a string from loop and do split. But is there more efficient and professional level of doing this?

You can use the keys method in lodash, https://lodash.com/docs#keys
You could also use the following code
var arr = [];
var o = {a:1,b:2}
for(k in o) { arr.push(k); }
Here is another version which goes deep into the object
function getKeys(o) { var arr = []; for(k in o) { arr.push(k); if(typeof(o[k]) === 'object') { arr.push(getKeys(o[k])); }} return arr; }
If you have an object like {a:1,b:2, c: {d:1, e:2}} you would get the return as ['a','b','c',['d','e']]
A completely flat version would be this one
function getKeys(o) { var arr = []; for(k in o) { arr.push(k); if(typeof(o[k]) === 'object') { for(j of getKeys(o[k])){ arr.push(j); } }} return arr; }

If you have the following hash
var o = {a:1,b:2,c:3};
Create a new empty array for storing the keys
var array_keys = new Array();
Then use a for loop to push the keys into the array
for (var key in o) {
array_keys.push(key);
}
You can then run alert(array_keys)

This is a solution that avoids the for...in that you mentioned. However, I think the for...in solution is much more elegant.
This will walk the prototype chain and return all properties as a recursive function. As well as remove all duplicates.
function getKeys(obj) {
var keys = Object.keys(obj);
var parent = Object.getPrototypeOf(obj);
if (!parent) {
return keys;
}
return keys.concat(getKeys(parent))
.filter(function (item, index, col) {
return col.indexOf(item) === index;
});
}
var a = { a: 1, b: 2 };
var b = Object.create(a);
b.a = 2;
b.c = 3;
var c = Object.create(b);
console.log(getKeys(c));

Related

get data from javascript object

I have weird object:
{"Cats":10,"Dogs":815,"Fishes":2}
How can I get full value from each piece of data
var t = {"Cats":10,"Dogs":815,"Fishes":2};
var keys = [];
for (var key in t) {
if (t.hasOwnProperty(key)) {
console.log(key)
}
}
I'm getting only the names without number
I can use JSON.stringify and then manipulate that object but maybe there is other way?
Probably I missing something?
the for...in statement iterate over the property names get the value by property name.
var t = {"Cats":10,"Dogs":815,"Fishes":2};
var keys = [];
for (var key in t) {
if (t.hasOwnProperty(key)) {
console.log(key, t[key])
}
}
If you would like to generate an array of values then use Object.keys and Array#map methods.
var t = { "Cats": 10, "Dogs": 815, "Fishes": 2};
var keys = Object.keys(t);
var values = keys.map(function(key) {
return t[key];
});
console.log(keys, values);
var t = {"Cats":10,"Dogs":815,"Fishes":2};
var keys = [];
for (var key in t) {
if (t.hasOwnProperty(key)) {
console.log(key, t[key])
}
}
You could get the own properties first with Object.keys and iterate then.
var t = { Cats: 10, Dogs: 815, Fishes: 2 },
keys = Object.keys(t);
keys.forEach(function (key) {
console.log(key, t[key]);
});
var t = {"Cats":10,"Dogs":815,"Fishes":2};
for (var key in t)
{
console.log(key, t[key]);
}

why Object.keys(data).sort() not work as expected?

I am trying to sort my object keys.
But when I'm printing my object, it always print bb first. Can anyone explain this?
It should print aa first ? I already sorted my keys.
My first key should be aa and then second should be bb.
Here is my code
var data = {
bb:"bb",
aa:"cc"
};
Object
.keys(data)
.sort();
console.log(data)
DEMO
Two things:
objects in JS have no order of elements, like arrays do
Object.keys returns an array of object keys, it does not modify the object itself, see the following example:
var data={bb:"bb",aa:"cc"};
var arr = Object.keys(data);
arr.sort();
console.log(arr); // the array IS modified,
// but it has nothing to do with the original object
try this
var data={bb:"bb",aa:"cc"};
var keys = Object.keys(data);
keys.sort();
var obj = {};
for(i = 0; i < keys.length; i++){
obj[keys[i]] = data[keys[i]];
}
console.log(obj);
There is not any method for sorting object keys in JavaScript but you can do this by a object prototype like this.
Object.prototype.sortKeys = function () {
var sorted = {},
key, a = [];
for (key in this) {
if (this.hasOwnProperty(key)) {
a.push(key);
}
}
a.sort();
for (key = 0; key < a.length; key++) {
sorted[a[key]] = this[a[key]];
}
return sorted;
}
var data = {bb: "bb", aa :"cc"};
alert(JSON.stringify(data.sortKeys())); // Returns sorted object data by their keys

How to flatten or combine member names into one list?

For example if I have something like so:
var Constants = {
scope:{
namespaceA: { A_X: "TEST_AX" , A_Y: "TEST_AY" },
namespaceN: { N_X: "TEST_NX" , N_Y: "TEST_NY" }
}
_mapping: [],
getMapping: function(){...}
}
var flattenList = flatten(Constants.scope); //returns ["TEST_AX","TEST_AY","TEST_NX","TEST_NY"]
var anotherWayFlattened = flatten(Constants.scope.namespaceA,Constants.scope.namespaceB); //returns same result as above
EDIT: one way would be to iterate over the scope via for-each loop but I was looking for something more elegent?
DOUBLE EDIT: ok I just whipped something up like so:
var flattenedList = (function(list){
var flatList = []
$.each(list,function(i,items){
for(var p in items) flatList.push(items[p]);
})
return flatList;
})([Constants.scope.namespaceA,Constants.scope.namespaceB]);
but was wondering if we can avoid passing in the particular property and just pass in Constants and search for the list of namespaces
[Constants.scope.namespaceA,Constants.scope.namespaceB]
I'm wondering why you pass the sub-objects explicitly in an array. Why not just pass the whole Constants.scope object?
var flattenedList = (function(obj){
var flatList = []
for (var prop in obj) {
var items = obj[prop];
for (var p in items)
flatList.push(items[p]);
}
return flatList;
})(Constants.scope);
From your comment it looks like you wanted this:
var flattenedList = (function(obj, test){
var flatList = []
for (var prop in obj) {
if (!test(prop))
continue;
var items = obj[prop];
for (var p in items)
flatList.push(items[p]);
}
return flatList;
})(Constants, function(name) {
return name.substr(0, 9) == "namespace";
// or maybe
return /^namespace[A-Z]$/.test(name);
});
if you wanted to recurse to any (non cyclical!) depth, you could do this :
function flattenList(list, accumulator){
accumulator = accumulator || [];
for(var p in list){
if(list.hasOwnProperty(p)) {
if(typeof list[p] === "string") {
accumulator.push(list[p]);
} else if(typeof list[p] === "object") { // this is not a reliable test!
flattenList(list[p], accumulator);
}
}
}
return accumulator;
}
This code makes a number of assumptions - we only have strings at the end of our objects etc. Alternatively, if you know the depth in advance, your current solution can be optimized by using concat :
var flattenedList = (function(list){
return Array.prototype.concat.apply([], list);
})([Constants.scope.namespaceA,Constants.scope.namespaceB]);
Here's an approach that allows for deeper nesting. I know that wasn't part of the goals, but I found it a more interesting problem. :-)
var flatten = (function() {
var toString = Object.prototype.toString, slice = Array.prototype.slice;
var flatten = function(input, output) {
var value;
output = (toString.call(output) == "[object Array]") ? output : [];
for (name in input) {if (input.hasOwnProperty(name)) {
value = input[name];
if (toString.call(value) == "[object Object]") {
flatten(value, output);
} else {
output.push(value);
}
}};
return output;
};
var merge = function(first, second) {
return first.concat(second);
}
return function() {
return slice.call(arguments).map(flatten).reduce(merge);
};
}());
This allows either approach:
flatten(Constants.scope);
flatten(Constants.scope.namespaceA, Constants.scope.namespaceN);
You can pass in as many separate arguments as you like, or one argument. They'll all be searched to arbitrary depths.
For some environments, you might have to shim Array.prototype functions map and reduce.

Copy an arbitrary n-dimensional array in JavaScript?

I am basically looking for a general function copy(array) that will return identical n-dimensional array without any references to the former one.
This works for arrays, it won't work for nested objects (that aren't Arrays):
function copy(arr){
var new_arr = arr.slice(0);
for(var i = new_arr.length; i--;)
if(new_arr[i] instanceof Array)
new_arr[i] = copy(new_arr[i]);
return new_arr;
}
Use it like this:
var arr = [
[[1,2,3],[75]], 100,
[[[1]]], [],
[1,[2,[3],4],5], 6, 7, 8
];
var new_arr = copy(arr);
Using jQuery (works for arrays and "plain" objects):
var a = [[1,[2,3]],[4]];
var b = $.extend(true, [], a);
a[0][0] = 42; // modify object in a
alert(JSON.stringify(b)); // [[1,[2,3]],[4]]
Or JSON direct (if all objects are JSON-izable):
var a = [[1,[2,3]],[4]];
var b = JSON.parse(JSON.stringify(a))
a[0][0] = 42; // modify object in a
alert(JSON.stringify(b)); // [[1,[2,3]],[4]]
Older versions of IE (8? 7?) will need a shim for the JSON object.
I just wanted to add to Paulpro's answer. Note that this is identical to his answer except that I changed copy(new_arr[i]) to copy(arr[i]), and new_arr.length to arr.length.
function copy(arr){
var new_arr = arr.slice(0);
for(var i = arr.length; i--;)
if(new_arr[i] instanceof Array)
new_arr[i] = copy(arr[i]);
return new_arr;
}
The reason copy(new_arr[i]) worked is because the .slice copied over what arr[i] was pointing at, making them equal.
Also, while Paulpro's answer works for all cases, if by chance each member of each dimension of the multi-dimensional array is either an array or a non-array you can make it more efficient by only slicing non-array dimensions.
I mean what is the point of copying over an array of pointers that will simply be overwritten by the following recursion?
function copy(arr){
if(arr[0] instanceof Array){
var new_arr = new Array(arr.length);
for(var i = arr.length; i--;)
new_arr[i] = copy(arr[i]);
}
else{var new_arr = arr.slice(0);}
return new_arr;
}
This is my solution to clone a multidimensional array; Actually i had to invent Array.prototype.clone() in order to invent a function to generate N dimension array and initialize it with a value.
Array.prototype.clone = function(){
return this.reduce((p,c,i) => (p[i] = Array.isArray(c) ? c.clone() : c, p),[])
}
function arrayND(...n){
return n.reduceRight((p,c) => c = (new Array(c)).fill(true).map(e => Array.isArray(p) ? p.clone() : p ));
}
var arr = arrayND(...[4,4,4],8); //last argument is the initializing value
arr[0][1][3] = "eight";
console.log(JSON.stringify(arr));

How to get object length [duplicate]

This question already has answers here:
Length of a JavaScript object
(43 answers)
Closed 3 years ago.
Is there any built-in function that can return the length of an object?
For example, I have a = { 'a':1,'b':2,'c':3 } which should return 3. If I use a.length it returns undefined.
It could be a simple loop function, but I'd like to know if there's a built-in function?
There is a related question (Length of a JSON object) - in the chosen answer the user advises to transform object into an array, which is not pretty comfortable for my task.
For browsers supporting Object.keys() you can simply do:
Object.keys(a).length;
Otherwise (notably in IE < 9), you can loop through the object yourself with a for (x in y) loop:
var count = 0;
var i;
for (i in a) {
if (a.hasOwnProperty(i)) {
count++;
}
}
The hasOwnProperty is there to make sure that you're only counting properties from the object literal, and not properties it "inherits" from its prototype.
This should do it:
Object.keys(a).length
However, Object.keys is not supported in IE8 and below, Opera and FF 3.6 and below.
Live demo: http://jsfiddle.net/simevidas/nN84h/
Can be done easily with $.map():
var len = $.map(a, function(n, i) { return i; }).length;
Have you taken a look at underscore.js (http://underscorejs.org/docs/underscore.html)? It's a utility library with a lot of useful methods. There is a collection size method, as well as a toArray method, which may get you what you need.
_.size({one : 1, two : 2, three : 3});
=> 3
Summarizing all together, here is a universal function (including ie8 support):
var objSize = function(obj) {
var count = 0;
if (typeof obj == "object") {
if (Object.keys) {
count = Object.keys(obj).length;
} else if (window._) {
count = _.keys(obj).length;
} else if (window.$) {
count = $.map(obj, function() { return 1; }).length;
} else {
for (var key in obj) if (obj.hasOwnProperty(key)) count++;
}
}
return count;
};
document.write(objSize({ a: 1, b: 2, c: 3 }));
// 3
In jQuery i've made it in a such way:
len = function(obj) {
var L=0;
$.each(obj, function(i, elem) {
L++;
});
return L;
}
So one does not have to find and replace the Object.keys method, another approach would be this code early in the execution of the script:
if(!Object.keys)
{
Object.keys = function(obj)
{
return $.map(obj, function(v, k)
{
return k;
});
};
}
Also can be done in this way:
Object.entries(obj).length
For example:
let obj = { a: 1, b: 2, };
console.log(Object.entries(obj).length); //=> 2
// Object.entries(obj) => [ [ 'a', 1 ], [ 'b', 2 ] ]
Here's a jQuery-ised function of Innuendo's answer, ready for use.
$.extend({
keyCount : function(o) {
if(typeof o == "object") {
var i, count = 0;
for(i in o) {
if(o.hasOwnProperty(i)) {
count++;
}
}
return count;
} else {
return false;
}
}
});
Can be called like this:
var cnt = $.keyCount({"foo" : "bar"}); //cnt = 1;
One more answer:
var j = '[{"uid":"1","name":"Bingo Boy", "profile_img":"funtimes.jpg"},{"uid":"2","name":"Johnny Apples", "profile_img":"badtime.jpg"}]';
obj = Object.keys(j).length;
console.log(obj)
For those coming here to find the item count of something that is already a jQuery object:
.length is what you are looking for:
Example:
len = $('#divID').length;
alert(len);
If you want to avoid new dependencies you could make your own smart objects. Of course only if you want to do more that just get it's size.
MyNeatObj = function (obj) {
var length = null;
this.size = function () {
if (length === null) {
length = 0;
for (var key in obj) length++;
}
return length;
}
}
var thingy = new MyNeatObj(originalObj);
thingy.size();
You might have an undefined property in the object.
If using the method of Object.keys(data).length is used those properties will also be counted.
You might want to filter them out out.
Object.keys(data).filter((v) => {return data[v] !== undefined}).length
You may use something like Lodash lib and _.toLength(object) should give you the length of your object
You could add another name:value pair of length, and increment/decrement it appropriately. This way, when you need to query the length, you don't have to iterate through the entire objects properties every time, and you don't have to rely on a specific browser or library. It all depends on your goal, of course.

Categories

Resources