I am working with JavaScript, could you help me please
Here is my problem.
I have this object:
var MyObj= [{ a: 0, b: "Zero", c: "x", d: "!" }, { a: 1, b: "One", c: "y", d: "#" }]
I want to change the element of selected object ("a" --> "id") to become like this:
var NewObj= [{ id: 0, b: "Zero", c: "x", d: "!" }, { id: 1, b: "One", c: "y", d: "#" }]
I tried to use $.map() method like this
NewObj= $.map(MyObj, function (obj) {
return { id: obj.a, b: obj.b, c: obj.c, d:obj.d };
});
Is there any better way to do this since I only change one element of object?
No need for ES6 / Object.assign, no need for jQuery:
Working Fiddle: https://jsbin.com/gosaqid/edit?js,console
function makeObj(obj){
return obj.map(function(el, i) {
el.id = i;
delete el.a;
return el;
});
}
Not unless you have a clone/copy/extend function available. One is coming up in new JavaScript, and jQuery has one, and it's not very hard writing your own. But it still isn't a walk in the park - you can't just rename a property, you need to copy and delete:
NewObj = MyObj.map(function(obj) {
var newobj = Object.assign({}, obj, {id: obj.a});
delete newobj.a;
return newobj;
});
In your example MyObj is an array of objects.
var object = {}
var array = []
var arrayOfObjects = [{}, {}, {}]
In your desired result, you have changed one of the keys of every object in the array.
Using map is a perfectly adequate way of doing this, in fact JavaScript's array has a built in map method.
var newArrayOfObjects = arrayOfObjects.map(function (obj) {
return {
id: obj.a,
b: obj.b,
c: obj.c
}
})
If you have a ton of keys this can get a little verbose so you can use $.extend, but chances are you're writing code for modern browsers so the whole thing can be written as such:
var newArrayOfObjects = arrayOfObjects.map(obj =>
Object.assign({}, obj, { id: obj.a })
)
update: as #Amadan suggests, you can also delete the old key if you need
Related
I would like to create this JS function with these arguments:
transform([{a:1, b:'1', c:true},{a:'1', b:2, c:3, d:false}, {a:1, c:'test'}], ['a','b','c']);
First argument is an array of objects
Second one is array of keys.
I would like to get this output object:
{a:[1, '1', 1], b:['1', 2],c:[true, 3, 'test']}
As you can see the second argument became the keys to the created object
and all values under these keys where grouped together.
And maybe an option to pass a unique argument to function and get this (duplicate values removed):
{a:[1, '1'], b:['1', 2], c:[true, 3, 'test']}
What is the fast and/or elegant way to do it?
Is there any lodash/underscore helper for it?
As an additional generalism. How can the input (the first argument) be a generic collection with nested levels (array or object of nested levels of arrays or objects) ?
Thanks.
You can use Array.prototype.reduce
let param1 = [{a:1,b:'1',c:true},{a:'1',b:2,c:3,d:false},{a:1,c:'test'}];
let param2 = ['a', 'b', 'c'];
function test(objArr, keys) {
let returnObject = {};
keys.forEach(key => returnObject[key] = []);
return objArr.reduce((ret, obj) => {
keys.forEach(key => {
if (obj[key] !== undefined)
ret[key].push(obj[key]);
});
return ret;
}, returnObject);
}
console.log(JSON.stringify(test(param1, param2)));
Outputs:
{"a":[1,"1",1],"b":["1",2],"c":[true,3,"test"]}
Try this:
function transform(data,keys){
let results = {};
//loop all you keys
keys.forEach(index => {
//loop your arrays
data.forEach(element => {
//if there is a match add the key to the results object
if(index in element) {
if(!(index in results)) results[index] = [];
//check if a value already exists for a given key.
if(!(element[index] in results[index])) results[index].push(element[index]);
}
});
});
return results;
}
console.log(transform([{a:1,b:'1',c:true},{a:'1',b:2,c:3,d:false},{a:1,c:'test'}], ['a','b','c']));
You can loop over the key array and pass this key to another function which will use forEach method. This getMatchedKeyValues using forEachwill return an array of elements whose key matches
var arr = [{
a: 1,
b: '1',
c: true
}, {
a: '1',
b: 2,
c: 3,
d: false
}, {
a: 1,
c: 'test'
}];
var keys = ['a', 'b', 'c']
function transform(keyArray) {
var newObj = {};
// looping over key array
keyArray.forEach(function(item) {
// adding key property and calling a function which will return
// an array of elements whose key is same
newObj[item] = getMatchedKeyValues(item)
})
return newObj;
}
function getMatchedKeyValues(keyName) {
var valArray = [];
arr.forEach(function(item) {
if (item[keyName]) {
valArray.push(item[keyName])
}
})
return valArray;
}
console.log(transform(keys))
I coded below , pls have a look this solution.
function test(arr, arr1) {
return arr.reduce((total, current) => {
arr1.forEach(curr => {
if (typeof total[curr] === "undefined") total[curr] = [];
if (current[curr]) total[curr].push(current[curr]);
});
return total;
}, {});
}
console.log(
test(
[
{ a: 1, b: "1", c: true },
{ a: "1", b: 2, c: 3, d: false },
{ a: 1, c: "test" }
],
["a", "b", "c"]
)
);
Would like to merge an array of objects resulting in an object of unique keys and array of values (duplication of values is ok). Solutions in vanilla JS or lodash preferred.
eg - from this:
[{
a: 1,
b: 2
}, {
a: 1,
c: 3
}]
to this:
{
a: [1, 1],
b: [2],
c: [3]
}
You can use _.mergeWith() with the spread syntax to combine the objects:
const data = [{"a":1,"b":2},{"a":1,"c":3}];
const result = _.mergeWith({}, ...data, (v1 = [], v2) => [...v1, v2]);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
ES6 variant:
const a = [{
a: 1,
b: 2
}, {
a: 1,
c: 3
}]
const b = a.reduce((acc, cur) => Object.assign(acc,
...Object.keys(cur).map(key => ({ [key]: (acc[key] || []).concat(cur[key]) })))
, {})
console.log(b)
without loadash:
var t = [{
a: 1,
b: 2
}, {
a: 1,
c: 3
}];
var result = {};
debugger;
for(var i=0; i<t.length; i++){
for(var j in t[i]){
if(result.hasOwnProperty(j)){
result[j].push(t[i][j]);
}else{
result[j] = [t[i][j]];
}
}
}
console.log(result);
A quick search here in stack reveals that #elclanrs already wrote code for that here However based on the comments, it needs a little tweaking to accept an array of objects, so I added a bit of change to the original code itself.
so basically it boils to the function call:
var merge = function() {
return [].reduce.call(arguments, function(acc, x) {
for(i=0;i<x.length;i++){
Object.keys(x[i]).forEach(function(k) {
acc[k] = (acc[k]||[]).concat([x[i][k]])
});
}
return acc
},{})
}
}
Here's a snippet using the function call (with a bit of small change I put) in that post:
var x = [{a: 1, b: 2}, {a: 1,c: 3}]
var merge = function() {
return [].reduce.call(arguments, function(acc, x) {
for(i=0;i<x.length;i++){
Object.keys(x[i]).forEach(function(k) {
acc[k] = (acc[k]||[]).concat([x[i][k]])
});
}
return acc
},{})
}
y = merge(x);
alert(JSON.stringify(y));
You can use lodash#mergeWith wrapped in a lodash#spread to make lodash#mergeWith treat an array as a list of arguments. We use lodash#concat as a supporting function to concatenate an empty object (to avoid mutating the objects in the collection), the collection, and the customizer function that merges the entire collection. The customizer is composed using lodash#flow, wherein its first argument is lodash#concat that only accepts an arity of 2 using lodash#ary and the second argument uses lodash#compact -- It removes all undefined values in an array.
var result = _.spread(_.mergeWith)(
_.concat({}, data, _.flow(_.ary(_.concat, 2), _.compact))
);
var data = [{
"a": 1,
"b": 2
}, {
"a": 1,
"c": 3
}];
var result = _.spread(_.mergeWith)(
_.concat({}, data, _.flow(_.ary(_.concat, 2), _.compact))
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
I want to send a javascript object like this one through a $.ajax request :
var o = {
a: 1,
b: 'dummy string',
c: ['a', 1, {}],
d: {dd: 1},
e: new Date(),
f: function() {
console.log('here');
}
}
I know that i normally should use JSON.stringify before sending it to my php script. The problem is JSON.stringify, removes the properties it can't stringify :
JSON.stringify(o);
returns this ->
"{
"a":1,
"b":"dummy string",
"c":["a",1,{}],
"d":{"dd":1},
"e":"2015-11-13T21:34:36.667Z"
}"
But what shoud i do, if i want to store in a mysql column the "o" javascript object as plain text like this :
o = {
a: 1,
b: 'dummy string',
c: ['a', 1, {}],
d: {dd: 1},
e: new Date(),
f: function() {
console.log('here');
}
}
You could try this:
var o = {
a: 1,
b: 'dummy string',
c: ['a', 1, {}],
d: {dd: 1},
e: new Date(),
f: function() {
console.log('here');
}
};
o.f = o.f.toString();
var stringy = JSON.stringify(o);
document.getElementById('test2').innerHTML = stringy;
Fiddle: http://jsfiddle.net/e2cxandt/
Obviously this needs to be changed a bit so you aren't overwriting the function by maybe cloning the object but as a quick example you can see it now has the property in the string.
As someone mentioned in the comments above, war10ck, here is an example of using the replacer argument of JSON.stringify
var o = {
a: 1,
b: 'dummy string',
c: ['a', 1, {}],
d: {dd: 1},
e: new Date(),
f: function() {
console.log('here');
}
};
function replacer (key, value) {
if (typeof value === "function") {
return value.toString();
}
return value;
}
var stringy2 = JSON.stringify(o, replacer);
document.getElementById('test2').innerHTML = stringy2;
Fiddle: http://jsfiddle.net/e2cxandt/1/
a couple universal (non-specific-instance) options:
you can define a custon toJSON on any object:
Function.prototype.toJSON=function(){return String(this);};
JSON.stringify({a:1, b:function(){alert(123)}});
which shows:
{"a":1,"b":"function (){alert(123)}"}
the one caveat is that your function literal is quoted as a string and no longer a function. to fix that if needed, you can use a reviver parameter to JSON.parse().
a better option:
using a replace arg to JSON.stringify():
JSON.stringify({a:1, b:function(){alert(123)}}, function(k,v){
if(typeof v==="function") return String(v);
return v;
});
which shows:
{"a":1,"b":"function (){alert(123)}"}
that way is particularly nice because you need not modify an built-in or instance objects.
I have an object in my .js file (node)
var z = [
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'},
{'a': 'uno', 'b': 'dos'}
];
I would like to omit each 'a' from z object.
I'm trying with something like this, but is not working.
var y = _.forEach(z, function(n){
//console.log(_.omit(n, 'a'));
return _.omit(n, 'a');
});
console.log(y);
I tried without return, and few ways more, but didn't get it.
My jsfiddle link: http://jsfiddle.net/baumannzone/jzs6n78m/
Any help? Cheers!
Create a new array of objects, by omitting a from each of them
console.log(_.map(z, function (obj) {
return _.omit(obj, 'a');
}));
// [ { b: 'dos' }, { b: 'dos' }, { b: 'dos' }, { b: 'dos' } ]
As it is, you are omitting and creating a new object but that object is ignored by _.each. Now, we use _.map, which will gather all the values returned from the function and form a new array.
If you prefer a one-liner, create a partial function and leave only the object to be used as _, like this
console.log(_.map(z, _.partial(_.omit, _, 'a')));
// [ { b: 'dos' }, { b: 'dos' }, { b: 'dos' }, { b: 'dos' } ]
var y = _.map(z, function(n) {
return _.omit(n, 'a');
});
This will create a new array from the old one, mapping the objects in z to new objects that omit the 'a' attribute.
An alternative is to use chaining, so:
var y = _(z).map(function(n){return n.omit('a');}).value();
B
I want to add multiple attributes to an existing object with existing attributes. Is there a more concise way than one line per new attribute?
myObject.name = 'don';
myObject.gender = 'male';
Everything on MDN shows how to do new objects with bracket notation, but not existing objects: https://developer.mozilla.org/en-US/docs/JavaScript/Guide/Working_with_Objects
In ES6/ ES2015 you can use the Object.assign method
let obj = {key1: true};
console.log('old obj: ', obj);
let newObj = {key2: false, key3: false};
Object.assign(obj, newObj);
console.log('modified obj: ', obj);
I'm not sure if that's helpful, but there is a trick using JS ES6 spread syntax:
let obj = {a: 1, b: 2};
obj = {...obj, b: 3, c: 4};
console.log(obj); // {a: 1, b: 3, c: 4}
You can try to use this somehow... In general, that's a single liner to add or override object properties using js destructuring method.
Edit:
Notice that the placement of ...obj in the new object is cruicial, as placing it first would allow overriding it with the following params (b: 3, c: 4 in my example), and placing it last will give priority to the members that are already in the object.
From How can I merge properties of two JavaScript objects dynamically?
var obj2 = {name: 'don', gender: 'male'};
for (var attrname in myobject) { myobject[attrname] = obj2[attrname]; }
EDIT
To be a bit clearer about how you could extend Object to use this function:
//Extend the protype so you can make calls on the instance
Object.prototype.merge = function(obj2) {
for (var attrname in obj2) {
this[attrname] = obj2[attrname];
}
//Returning this is optional and certainly up to your implementation.
//It allows for nice method chaining.
return this;
};
//Append to the object constructor function so you can only make static calls
Object.merge2 = function(obj1, obj2) {
for (var attrname in obj2) {
obj1[attrname] = obj2[attrname];
}
//Returning obj1 is optional and certainly up to your implementation
return obj1;
};
Usage:
var myObject1 = { One: "One" };
myObject1.merge({ Two: "Two" }).merge({ Three: "Three" });
//myObject1 is { One: "One", Two: "Two", Three: "Three", merge: function }
var myObject2 = Object.merge2({ One: "One" }, { Two: "Two" });
Object.merge2(myObject2, { Three: "Three" });
//myObject2 is { One: "One", Two: "Two", Three: "Three" }
Note: You certainly could implement a flexible merge conflict strategy depending on your needs.
Use jQuery library
jQuery.extend(myObject, { name : 'don', gender : 'male' });
Sometimes I do it like this:
var props = {
name : 'don',
gender : 'male',
age : 12,
other : false
};
for(var p in props) myObject[p] = props[p];
In ECMAscript 5 you can make us of defineProperties:
Object.defineProperties(myobject, {
name: {
value: 'don'
},
gender: {
value: 'male'
}
});