how to concatenate two object and replace the values? - javascript

I'm trying to concatenate two objects. I need to merge the two object and based on the "beforeVist" object value within the arrow.
My two objects down below:
const beforeVist = {
name : '<<name>>',
age : '<<age>>',
place : '<<place>>'
};
const afterVist = {
name : 'Robin',
age : 22,
place : 'Mars'
}
var Updated = {...afterVist, ...beforeVist};
console.log(Updated)
when I'm trying do console.log() function output below,
{
name : 'Robin',
age : 22,
place : 'Mars'
}
this is what my expected output is. I'm not sure that it is the right way.
Thanks advance!!!

You could also use Object.assign
const a = {p1: 12, p2: 23}
const b = {p2: 34, p3: 'adfa'}
let c = Object.assign(b, a)
// c contains:
{p2: 23, p3: "adfa", p1: 12}
If you care about immutability, you can provide separate "result" object:
const res = Object.assign({}, b, a)
// a and b still hold the original values
NOTE: properties ORDER will be driven from left-to-right ("p2" is the first prop in B, but second in A), but the VALUES from right-to-left(result.p2 contains value from the rightMost object with such property - ie A.p2 overrides B.p2

It is the right way. You should use object sprad
let merged = {...obj1, ...obj2};
Method for ES5 and Earlier
for (var attrname in obj2) { obj1[attrname] = obj2[attrname]; }
Because << >> are always at the first two places and the last two places we can simply slice and then reassign the value.
const beforeVist = {
name: '<<name>>',
age: '<<age>>',
place: '<<place>>'
};
const afterVist = {
name: '<<Robin>>',
age: '<<22>>',
place: '<<Mars>>'
}
var Updated = {...beforeVist, ...afterVist };
Object.entries(Updated).forEach(([key, value]) => {
let val = value.slice(2, value.length - 2);
Updated[key] = val;
})
console.log(Updated)

At the moment you are just overwriting the properties from afterVist with the properties in beforeVist, and since the property names are the same, you're essentially just making a shallow copy. This is more evident if your afterVist has different property names to beforeVist (and why I've provided different property names in beforeVist below - to show that they don't have to be the same and that the value is grabbed based on the key specified in <<key>>)
Instead, you can use Object.fromEntries() by mapping the Object.entries() of your original object, and using replace on the keys to extract the key name like so:
const beforeVist = { myName: '<<name>>', myAge: '<<age>>', myPlace: '<<place>>' };
const afterVist = { name: 'Robin', age: 22, place: 'Mars' };
const result = Object.fromEntries(Object.entries(beforeVist).map(([key, value]) => [
key,
value.replace(/<<([^>>]*)>>/, (_, g) => afterVist[g])
]));
console.log(result);

Related

How do you convert an object with duplicate keys to JSON/String?

Imagine you have an object like this:
var obj = {
name: "Mike",
name: "George",
age: 24,
}
Converting this to JSON with JSON.stringify(obj) yields:
{"name":"George","age":24}
This causes loss of data and isn't something we want.
Converting this to a string with toString() yields
[object Object]
, which isn't what we want either.
How does one go about this?
PS: I am aware that objects can't have two identical keys.
So after some brainstorming with the nice users that have commented here, a simple way to deal with this is to just turn it into a string manually. Like this:
var obj = `
name: "Mike",
name: "George",
age: 24,
`;
Then just parse it to your heart's content. For me personally, this could be a way to do it. However, this will obviously depend on the user-case.
var obj2 = {};
str = str.split(",").map(e => e.replace(/(\")/gi, "").trim());
str.forEach((e, i) => {
var temp = e.slice(0, e.indexOf(":"));
if(obj2[temp]) obj2[temp].push(e.slice(e.indexOf(":") + 1).trim());
else obj2[e.slice(0, e.indexOf(":"))] = [e.slice(e.indexOf(":") + 1).trim()];
})
The code above just splits the string based on some desired separator and processes the given array further. This might be a indelicate way to solve the question, but it works for my scenario :/. It yields the following JSON-object:
{"name":["Mike","George"],"age":["24"]}
Right after your object is defined, the second "name" key will override the first "name" key.
You can re-structure your object like this:
var obj = {
name: ["Mike","George"],
age: 24,
}
or
var arrayObj = [{
name: "Mike",
age: 24,
},{
name: "George",
age: 24,
}]
and use the built-in function for string in js to get your expected result.
Hope this helps!
You can't do it. the "name" value is the second value assigned to "name" key in javascript object or JSON. try to use obj.name it will be "George"
This is workaround to do what are you need.you can use "_" or any unused symbol.
const obj = {
name: 'ahmed',
_name: 'elmetwally',
title: 'js dev',
};
console.log(JSON.stringify(obj).replace(/\_/g, ''));
Here's a simple method to convert a string representation of the object into an array of key-value pairs.
It's not a general method, but it should work fine for an object with no nesting.
let result = document.getElementById('result');
let jsonStr = `{ name: "Mike", name: "George", age: 24 }`;
result.innerHTML = `jsonStr: "${jsonStr}"\n`;
// strip out '{}'
let jsonClean = jsonStr.replace(/{/g, '').replace(/}/g, '');
result.innerHTML += `jsonClean: "${jsonClean}"\n`;
// split jsonClean into array of key-value strings
let kvStrings = jsonClean.split(',');
result.innerHTML +=
`kvStrings: ${JSON.stringify(kvStrings)}\n`;
// form array of key-value pairs
let kvPairs = kvStrings.map(kvstr => {
let [key, value] = kvstr.split(':').map(el => el.trim());
// strip double quotes or convert to number
if (value.includes('"')) {
value = value.replace(/"/g, '');
} else {
value = Number.parseFloat(value);
}
return [key, value];
});
result.innerHTML += `kvPairs: ${JSON.stringify(kvPairs)}`;
<pre id="result"></pre>
So after some brainstorming with the nice users that have commented here, a simple way to deal with this is to just turn it into a string manually. Like this:
var obj = `
name: "Mike",
name: "George",
age: 24,
`;
Then just parse it to your heart's content. For me personally, this could be a way to do it. However, this will obviously depend on the user-case.
var obj2 = {};
str = str.split(",").map(e => e.replace(/(\")/gi, "").trim());
str.forEach((e, i) => {
var temp = e.slice(0, e.indexOf(":"));
if(obj2[temp]) obj2[temp].push(e.slice(e.indexOf(":") + 1).trim());
else obj2[e.slice(0, e.indexOf(":"))] = [e.slice(e.indexOf(":") + 1).trim()];
})
The code above just splits the string based on some desired separator and processes the given array further. This might be a indelicate way to solve the question, but it works for my scenario :/. It yields the following JSON-object:
{"name":["Mike","George"],"age":["24"]}

Filtering one object with another array's object key

I am trying to filter an object with another object inside of an array.
To be more precise, I am trying to compare the keys of the object inside the array, to the keys of my main object. If the values are the same, I want to return the value corresponding to those keys.
Here's an example:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}]
I wanna check if any of the keys in object b are inside object a and if they are, I want to return their value into array. For example, I want to return ["A++","D","C+"]
I've tried using filter and Array.prototype.some but I couldn't figure out anything. Any advice on how should I achieve this?
First make an array or Set of all the keys inside b, then use .map to access each key on the a object:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}];
const keys = b.flatMap(Object.keys);
const arr = keys.map(key => a[key]);
console.log(arr);
I'm assuming that you want to handle multiple objects in b.
If so and if you want one array for each object in b then you could do something like:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
},{
"maths":"Mathematics",
"biology":"Biology",
"english":"English"
}]
const result = b.map(obj => Object.keys(obj).map(key => a[key]));
console.log(result);
If you are dealing with a single object in the array b, then you can do this:
var a = {
"maths":"A++",
"literature":"C-",
"sports":"B+",
"biology":"D",
"chemistry":"A",
"english":"A+",
"physics":"C+"
}
var b = [{
"maths":"Mathematics",
"biology":"Biology",
"physics":"Physics"
}]
const valuesInAndB = Object.keys(a).reduce((acc,x) => {
if (b[0][x]) {
return acc.concat(a[x]);
}
return acc;
}, []);
console.log(valuesInAndB);
However, if the objects in b will be greater than one then as answered by #certainperformance you could get all the keys in b and map through a with those keys.
const keysInB = b.flatMap(Object.keys);
keysInB.map(key => a[key]);
flatMap is not available in some older browsers, please keep that in mind.

Javascript switch keys for a hash

Is there an equivalent method available in javascript to switch keys in a hash
For example
Eg. {x: 50, y: 75, data: 99}, to {x: 50, y: 99, data: 75}
I would use reduce
hash = { name: 'Rob', age: '28' }
Object.keys(hash).reduce((object, key) => {
object[key.toUpperCase()] = hash[key];
console.log(object);
return object;
}, {});
Basically, what is happening is I iterate over an array of the hash object's keys. For each key, I alter an empty object (the last argument), declaring that key with the required transformations as a property on that object and then assigning it the value of the corresponding property on the hash object. The altered object is then used in place of the initial empty object, and the function calls itself recursively until the end of the array. Reduce is awesome and if you're new to JS I highly suggest learning more about it! All of the functional array methods (map, filter, reduce, forEach) are worth looking into.
Read more about reduce here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/Reduce?v=a
You're going to have to write a function to swap object keys
const propSwap = (obj1, key1, key2, obj2) => {
obj2 = obj2 || JSON.parse(JSON.stringify(obj1));
obj1[key2] = obj2[key1];
obj1[key1] = obj2[key2];
return obj1;
}
that first line makes it so that obj2 is an optional argument
unfortunately the javascript standard library isn't extremely deep but you can accomplish those two operations separately using the methods I've outlined above. If you have any questions let me know!
You could do something like this:
const transformed = Object.entries(hash).reduce((aggr, [key, value]) => {
aggr[key.toUpperCase()] = value;
return aggr;
}, {});

Sum values of collection by type and assign to new property on replicated object

I'm trying to sum values from a collection and add them to a new property for each object
var collection = [
{prop:'title',quan:2},
{prop:'body',quan:3},
{prop:'title',quan:2},
{prop:'title',quan:4},
]
/* desired result
[
{prop:'title', quan:2, stock:8},
{prop:'body', quan:3, stock:3},
{prop:'title', quan:2, stock:8},
{prop:'title', quan:4, stock:8},
]
*/
I've tried many different ways with no success. I am trying to do this in a functional way.
This were I am currently stuck and I'm quite sure it is the most concise way.
// group the props using key
var result = _.groupBy(collection,'prop');
which outputs
{
title:[
{prop:'title',quan:2},{prop:'title',quan:2},{prop:'title',quan:4}
],
body:[
{prop:'body':quan:3}
]
}
So let's reduce the arrays we've created
var obj = {};
_.forEach(result,function(value,key){
obj[key] = _.reduce(value,function(acc,val){
return acc.quan + val.quan
});
});
This section above isn't working though?
When I have that working, I should be able to map it back to my final collection.
we know totals, map them to collection
var final = _.map(collection,function(value){
return {
type:value.prop,
val:value.quan,
stock:obj[value.prop]
}
});
jsbin
First you have to get the sum object and then assign the sum to the corresponding object. Like this:
function stock(arr) {
// using lodach: var sum = _.reduce(arr, ...)
var sum = arr.reduce(function(s, o) { // get the sum object (hashing)
s[o.prop] = (s[o.prop] || 0) + o.quan; // if the sum already contains an entry for this object porp then add it to its quan otherwise add 0
return s;
}, {});
// using lodash: _.forEach(arr, ...);
arr.forEach(function(o) { // assign the sum to the objects
o.stock = sum[o.prop]; // the stock for this object is the hash of it's prop from the sum object
});
}
var collection = [
{prop:'title',quan:2},
{prop:'body',quan:3},
{prop:'title',quan:2},
{prop:'title',quan:4},
]
stock(collection);
console.log(collection);
If you want to return a new array and leave the original intact, use map like you already did instead of forEach like this:
// using lodash: _.map(arr, ...);
return arr.map(function(o) { // create new objects with stock property
return {
prop: o.prop,
quan: o.quan,
stock: sum[o.prop]
};
// or in ecmascript: return Object.assign({}, o, {stock: sum[o.prop]});
});
And then you'll have to use it like this:
var newArray = stock(collection);
I like this solution better because it abstracts away the collation but allows you to control how items are collated using a higher-order function.
Notice how we don't talk about the kind or structure of data at all in the collateBy function – this keeps our function generic and allows for it to work on data of any shape.
collateBy takes a grouping function f and a reducing function g and a homogenous array of any type of data
// collateBy :: (a -> b) -> ((c,a) -> c) -> [a] -> Map(b:c)
const collateBy = f => g => xs => {
return xs.reduce((m,x) => {
let v = f(x)
return m.set(v, g(m.get(v), x))
}, new Map())
}
const collateByProp = collateBy (x => x.prop)
const assignTotalStock = xs => {
let stocks = collateByProp ((acc=0, {quan}) => acc + quan) (xs)
return xs.map(({prop, quan}) =>
({prop, quan, stock: stocks.get(prop)}))
}
var collection = [
{prop:'title',quan:2},
{prop:'body',quan:3},
{prop:'title',quan:2},
{prop:'title',quan:4},
]
console.log(assignTotalStock(collection))
// [ { prop: 'title', quan: 2, stock: 8 },
// { prop: 'body', quan: 3, stock: 3 },
// { prop: 'title', quan: 2, stock: 8 },
// { prop: 'title', quan: 4, stock: 8 } ]
Performing collations is very common when manipulating data, so it doesn't make sense to encode collation behaviour in each function that needs it. Instead, use a generic, higher-order function that captures only the essence of a collation computation, and specialize it using grouping function f and reducing function g

Get array of object's keys

I would like to get the keys of a JavaScript object as an array, either in jQuery or pure JavaScript.
Is there a less verbose way than this?
var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
for (var key in foo) {
keys.push(key);
}
Use Object.keys:
var foo = {
'alpha': 'puffin',
'beta': 'beagle'
};
var keys = Object.keys(foo);
console.log(keys) // ['alpha', 'beta']
// (or maybe some other order, keys are unordered).
This is an ES5 feature. This means it works in all modern browsers but will not work in legacy browsers.
The ES5-shim has a implementation of Object.keys you can steal
You can use jQuery's $.map.
var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' },
keys = $.map(foo, function(v, i){
return i;
});
Of course, Object.keys() is the best way to get an Object's keys. If it's not available in your environment, it can be trivially shimmed using code such as in your example (except you'd need to take into account your loop will iterate over all properties up the prototype chain, unlike Object.keys()'s behaviour).
However, your example code...
var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
for (var key in foo) {
keys.push(key);
}
jsFiddle.
...could be modified. You can do the assignment right in the variable part.
var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [], i = 0;
for (keys[i++] in foo) {}
jsFiddle.
Of course, this behaviour is different to what Object.keys() actually does (jsFiddle). You could simply use the shim on the MDN documentation.
In case you're here looking for something to list the keys of an n-depth nested object as a flat array:
const getObjectKeys = (obj, prefix = '') => {
return Object.entries(obj).reduce((collector, [key, val]) => {
const newKeys = [ ...collector, prefix ? `${prefix}.${key}` : key ]
if (Object.prototype.toString.call(val) === '[object Object]') {
const newPrefix = prefix ? `${prefix}.${key}` : key
const otherKeys = getObjectKeys(val, newPrefix)
return [ ...newKeys, ...otherKeys ]
}
return newKeys
}, [])
}
console.log(getObjectKeys({a: 1, b: 2, c: { d: 3, e: { f: 4 }}}))
I don't know about less verbose but I was inspired to coerce the following onto one line by the one-liner request, don't know how Pythonic it is though ;)
var keys = (function(o){var ks=[]; for(var k in o) ks.push(k); return ks})(foo);
Summary
For getting all of the keys of an Object you can use Object.keys(). Object.keys() takes an object as an argument and returns an array of all the keys.
Example:
const object = {
a: 'string1',
b: 42,
c: 34
};
const keys = Object.keys(object)
console.log(keys);
console.log(keys.length) // we can easily access the total amount of properties the object has
In the above example we store an array of keys in the keys const. We then can easily access the amount of properties on the object by checking the length of the keys array.
Getting the values with: Object.values()
The complementary function of Object.keys() is Object.values(). This function takes an object as an argument and returns an array of values. For example:
const object = {
a: 'random',
b: 22,
c: true
};
console.log(Object.values(object));
Year 2022 and JavaScript still does not have a sound way to work with hashes?
This issues a warning but works:
Object.prototype.keys = function() { return Object.keys(this) }
console.log("Keys of an object: ", { a:1, b:2 }.keys() )
// Keys of an object: Array [ "a", "b" ]
// WARN: Line 8:1: Object prototype is read only, properties should not be added no-extend-native
That said, Extending Built-in Objects is Controversial.
If you decide to use Underscore.js you better do
var foo = { 'alpha' : 'puffin', 'beta' : 'beagle' };
var keys = [];
_.each( foo, function( val, key ) {
keys.push(key);
});
console.log(keys);

Categories

Resources