obj = {'a':['hello', 'hie'], 'b':['World', 'India']}
To
array = [{'a':'hello','b':'World'}, {'a':'hie','b':'India'}]
Best way to convert this or any build-in method for this conversion using JQuery.
Try this Code,
obj = {'a':['hello', 'hie'], 'b':['World', 'India']}
var key = Object.keys(obj);
array = [];
for (var i = 0; i < obj['a'].length; i++){
o = {}
for (k in key){
o[key[k]] = obj[key[k]][i]
}
array.push(o)
}
var obj = {'a':['hello', 'hie'], 'b':['World', 'India']};
var array = [];
for (var prop in obj)
for (var i=0; i<obj[prop].length; i++) {
var o = array[i] || (array[i] = {});
o[prop] = obj[prop][i];
}
No jQuery needed. With jQuery, it might look like this:
var array = [];
$.each(obj, function(prop) {
$.each(this, function(i) {
var o = array[i] || (array[i] = {});
o[prop] = this;
});
});
slower and less readable. Do not use.
Related
I want to count how often a number in an Array occurs. For example, in Python I can use Collections.Counter to create a dictionary of how frequently an item occurs in a list.
This is as far as I've gotten in JavaScript:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
/* obj[array[i]] = +=1 */ <= pseudo code
}
How can I create this frequency counter object?
Close but you can't increment undefined so you need to set initial value if it doesn't exist
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0) +1 ;
}
You were almost there. See below code:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = (obj[array[i]] || 0 ) +1;
}
console.log(obj);
Create an object and check if that specific key exist.If exist then increase it's value by 1
var array = [1, 4, 4, 5, 5, 7];
var obj = {};
for (var i = 0; i < array.length; i++) {
if (obj.hasOwnProperty(array[i])) {
obj[array[i]] += 1;
} else {
obj[array[i]] = 1;
}
}
console.log(obj)
You can use the ? : ternary operator to set initial value as 1 and then increment it on subsequent matches.
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]]?obj[array[i]]+1:1;
}
console.log(obj);
If the array is always going to be same, and you are going to check frequency of multiple items in the same array without it it being modified, #JohanP's answer is good.
But if you are only going to check frequency of only one item, or the array can change, creating the object is nothing but extra overhead.
In that case, you can do something like this:
const getItemFrequency = function(array, item) {
return array.filter(i => i === item).length;
}
var array = [1,4,4,5,5,7];
console.log(getItemFrequency(array, 4));
Concise logic written as proper function:
function countArrayItemFrequecy(array) {
const length = array.length;
const map = {};
for ( let i = 0; i < length; i++ ) {
let currentItem = array[i];
if (typeof map[currentItem] !== 'undefined' ) {
map[currentItem]++
} else {
map[currentItem] = 1
}
}
return map;
}
You need to make sure to assign default value to your frequency object for the first occurrence of the item. As a shortcut you can use ternary operator
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
obj[array[i]] = obj[array[i]] ? obj[array[i]]++ : 1;
}
which is the same as:
var array = [1,4,4,5,5,7];
var obj = {};
for (var i=0; i < array.length; i++) {
if (obj[array[i]]) {
obj[array[i]]++;
} else {
obj[array[i]] = 1;
}
}
You can use Object.assign: below clones map and then increments/adds the counter. These are pure (no side effects/param reassignment), single-purpose functions.
addToMap does the same thing as { ...map, map[e]: [e]: (map[e] || 0) + 1 }, but that requires babel.
const addToMap = (map, e) => Object.assign({}, map, { [e]: (map[e] || 0) + 1 });
const buildMap = a => a.reduce(addToMap, {});
Using Array.reduce:
arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
Example:
var arr = [1,1,2,4,1,4];
var counts = arr.reduce(function (acc, item) {
acc[item] = (acc[item] || 0) + 1;
return acc;
}, {});
console.log(counts);
var a = {
element:'input',
parent:'div1',
name:'inp',
type:'text',
value:'aa'
}
I want to loop through this object starting from name attribute using for in loop
But I am unable to do this using for in loop
is there any way to loop through the object starting from the name attribute
Old way:
for (var key in a) {
if (a.hasOwnProperty(key)) {
// todo something with a[key]
}
}
ES6 way:
Object.keys(a).forEach(function(key) {
// todo something with a[key]
});
for(var prop in a) {
console.log(a[prop]);
}
You could do something like this:
var keys = Object.keys(a);
var length = keys.length;
var startAt = keys.indexOf("name");
for(var i = 0; i < length ; i++) {
var prop = keys[(i+startAt)%length];
console.log(prop, a[prop]);
}
Or:
var keys = Object.keys(a).sort(function(a,b){ return a !== "name" });
for(var i = 0; i < keys.length; i++) {
var prop = keys[i];
console.log(prop, a[prop]);
}
Or:
var keys = Object.keys(a);
var idx = keys.indexOf("name");
if(idx > 0) {
var tmp = keys[0];
keys[0] = keys[idx];
keys[idx] = tmp;
}
for(var i = 0; i < keys.length; i++) {
var prop = keys[i];
console.log(prop, a[prop]);
}
But keep in mind that objects are unordered lists even though most browsers keep object properties in the order in which they were added.
I believe you can do it as follows:
function loopFromIndex(input, index) {
var started = false;
for (var property in input) {
started = started || (index === property);
if (started) {
//process iteration
}
}
}
You are still looping the whole property set, but when you encounter the given index, you will start the real loop.
I have the following array
['.some_class &.green_mod','.some_class &.red_mod','another_class &.green_mod','another_class &.orange_mod']
I want to get this array from it:
['.some_class &.green_mod &.red_mod','another_class &.green_mod &.orange_mod']
Is it possible?
you can try:
var preArr = ['.some_class &.green_mod', '.some_class &.red_mod', 'another_class &.green_mod', 'another_class &.orange_mod'];
var newArr = [];
preArr.forEach(function (item) {
var has = false;
var preWords = item.split('&');
for (var i = 0; i < newArr.length; ++i) {
var newWords = newArr[i].split('&');
if (newWords[0] == preWords[0]) {
has = true;
for (var j = 0; j < preWords.length; ++j) {
if (newWords.indexOf(preWords[j]) < 0) {
newWords.push(preWords[j]);
}
}
newArr[i] = newWords.join('&');
}
}
if (!has) {
newArr.push(item);
}
});
console.log(newArr);
demo
var test = (function() {
var fmap1 = function(e) { return e.trim().split(/\s+/); };
var fmap2 = function(e) { return e.join(" "); };
var fsort = function(e1,e2) { return e1[0] == e2[0] ? 0 : e1[0] > e2[0] ? 1 : -1; };
return function test(a) {
var a1 = a.map(fmap1).sort(fsort);
var s, a2 = [];
for (var i = 0, l = a1.length; i < l; i++) {
if (s != a1[i][0]) {
s = a1[i][0];
a2.push([s]);
}
a1.push.apply(a2[a2.length - 1], a1[i].slice(1));
}
return a2.map(fmap2);
};
})();
var arr = [' .some_class &.green_mod',' another_class &.green_mod','.some_class &.red_mod','another_class &.orange_mod'];
console.log(test(arr));
This seems to work for me:
var arr = ['.some_class &.green_mod','.some_class &.red_mod','another_class &.green_mod','another_class &.orange_mod'];
var obj = {};
var finalArr = [];
for(var i=0,c=arr.length;i<c;i++)
{
var parts = arr[i].split(' ');
var key = parts[0];
if(!obj[key]) obj[key] = [];
obj[key].push(parts.slice(1).join(' '));
}
var keys = Object.keys(obj);
for(var i=0,c=keys.length;i<c;i++)
{
var key = keys[i];
finalArr.push(key+' '+obj[key].join(' '))
}
console.log(finalArr);
Basically just loop through each one, and use the first word as a key to an array of strings to be appended, then loop through the object and join the keys with all of their array elements.
N.B. References to key are the first word
Solution bellow for data like key+separator+value where you are sure that there is no duplication in keys or You do not care if values are duplicated
// maping function that treats part before separator as key and saves incremetaly
// all values under that key (duplicated vales are possible)
// only one separator per input entry is allowed
function mapFun (el, obj, separator) {
var e = el.split(separator);
var key = e[0];
var val = e[1];
obj[key] = obj[key] ? obj[key] + separator + val : separator + val;
}
function combineClasses (arr) {
var result = [];
var separator = ' &';
var obj = Object.create(null); // create empty object without any properties or inheritance chain
for (var i=0; i<arr.length; i++) {
mapFun(arr[i], obj, separator);
}
for (var p in obj) {
result.push (p + obj[p]);
}
return result;
}
combineClasses(arr);
Bellow solution will work for data like before and data like key+separator+value1+separator+value2 and will not allow for duplicated values for the same key
function mapFun (el, separator, obj) {
var parts = el.split(separator);
var key = parts[0];
if (!obj[key]) {
obj[key] = Object.create(null);
}
for (var i=1; i<parts.length; i++) {
obj[key][parts[i]] = null;
}
}
function combineClasses (arr) {
var result = [];
var separator = ' &';
var obj = Object.create(null); // create empty object without any properties
for (var i=0; i<arr.length; i++) {
mapFun(arr[i], separator, obj);
}
for (var p in obj) {
var values = Object.keys(obj[p]).join(separator);
result.push (p + separator + values);
}
return result;
}
combineClasses(arr);
arr is where Your data comes in
var arr = ['.some_class &.green_mod','.some_class &.red_mod','another_class &.green_mod','another_class &.orange_mod']
This question already has answers here:
Split array of objects into new arrays based on year of object's date
(3 answers)
Closed 9 years ago.
I was wondering how I could turn this:
var data = [
{id:1,option1:'short',option2:'red',option3:'gold'},
{id:2,option1:'short',option2:'red',option3:'silver'},
{id:3,option1:'short',option2:'blue',option3:'gold'},
{id:4,option1:'short',option2:'blue',option3:'silver'},
{id:5,option1:'long',option2:'red',option3:'gold'},
{id:6,option1:'long',option2:'red',option3:'silver'},
{id:7,option1:'long',option2:'blue',option3:'gold'},
{id:8,option1:'long',option2:'blue',option3:'silver'}]
Into something formatted like this using Jquery.
var new_data = {
short:{
red:{gold:1,silver:2},
blue:{gold:3,silver:4}
},
long:{
red:{gold:5,silver:6},
blue:{gold:7,silver:8}
}
}
That is easier than you might think. Try this:
function helper(obj,tree,value) {
for( var i=0, l=tree.length; i<l-1; i++) {
obj[tree[i]] = obj[tree[i]] || {};
obj = obj[tree[i]];
}
obj[tree[i]] = value;
}
var new_data = {}, l = data.length, i;
for( i=0; i<l; i++) {
helper(new_data,[data[i].option1,data[i].option2,data[i].option3],data[i].id);
}
This plain JS will do it:
var data = […];
var new_data = {};
for (var i=0; i<data.length; i++) {
var o = new_data;
for (var j=1; j<3; j++) {
var prop = data[i]["option"+j];
o = o[prop] || (o[prop] = {});
}
o[data[i]["option"+j]] = data[i].id;
}
But it looks easier to use that nested schema in the first place?
You can use .reduce() like this:
var new_data = data.reduce(function(res, obj) {
if (!res[obj.option1])
res[obj.option1] = {};
if (!res[obj.option1][obj.option2])
res[obj.option1][obj.option2] = {};
res[obj.option1][obj.option2][obj.option3] = obj.id;
return res;
}, {});
or like this:
var new_data = data.reduce(function(res, obj) {
var o = res;
for (var i = 1; i < 3; i++)
o = (o[obj["option" + i]] = o[obj["option" + i]] || {});
o[obj.option3] = obj.id;
return res;
}, {});
Not sure if this can even be done, but I'll ask anyway:
Suppose if I have an array of names:
['bob', 'sue', 'dan']
And I want to dynamically create an object from those names:
bob.sue.dan = 5;
Is it possible?
Here you go, will preserve existing objects:
var namespace = function(name, separator, container){
var ns = name.split(separator || '.'),
o = container || window,
i,
len;
for(i = 0, len = ns.length; i < len; i++){
o = o[ns[i]] = o[ns[i]] || {};
}
return o;
};
e.g. usage:
namespace("com.example.namespace");
com.example.namespace.test = function(){
alert("In namespaced function.");
};
or for your example using an array.
var ns = ['bob', 'sue', 'dan'];
namespace(ns.join('.'));
bob.sue.dan.foobar = true;
or extending an existing object:
var bob = {}
namespace("foo.bar",".",bob);
bob.foo.bar = true;
Edit: updated as requested:
var namespace = function(name, separator, container, val){
var ns = name.split(separator || '.'),
o = container || window, i, len;
for(i = 0, len = ns.length; i < len; i++){
var v = (i==len-1 && val) ? val : {};
o = o[ns[i]] = o[ns[i]] || v;
}
return o;
};
namespace("bob.sue.dan",null,null,5);
alert(bob.sue.dan);
See working example: http://jsfiddle.net/herostwist/hu6j9/
Then you can do:
function makeOjectTree(propNames) {
var name;
var o = {};
var result = o;
for (var i=0, iLen=propNames.length; i<iLen; i++) {
name = propNames[i];
if (!o[name]) {
o[name] = {};
o = o[name];
}
}
return result;
}
var names = ['bob', 'sue', 'dan'];
var objs = [];
for(var i=0; i<names.length; i++) {
objs.push(names[i]);
var val = (i==names.length-1) ? "5" : "{}";
eval(objs.join(".") + " = " + val);
}
alert(bob.sue.dan);
Demo: http://jsfiddle.net/EpZm2/1/
sure you can ...
var obj = 5;
var yourarray = ['bob', 'sue', 'dan'];
yourarray = yourarray.reverse();
for(e in yourarray) {
var tmpobj = obj;
obj = new Object();
obj[yourarray[e]] = tmpobj;
// if you already have an object
if (e+1 == yourarray.length) {
your_current_existing_object[yourarray[e]] = tmpobj;
}
}
Yes this is possible.
You can define new properties on an object this way:
var obj = {};
obj["bob"] = {};
obj["bob"]["sue"] = {};
obj["bob"]["sue"]["dan"] = 5;
So you can also do it with an array of property names ;)