How to do: All contents into one object in this case - javascript

I'm trying to modify object's key to given name + its key name and want to get all into one object.
Source:
aodl = {"name1": "Jhon", "name2": "Tiger", "name3": "Jack", ...}
When I tried
console.log(
Object.entries(aodl).map(([key, value]: [string, string]) => {
return { ["aodl_" + key]: value };
})
);
Then I get
[ {"aodl_name1": "Jhon"}, {"aodl_name2": "Tiger"}, {"aodl_name3": "Jack"}, {…}, {…}, ...]
I want to get all object's contents and I want to put them into one object
{
"aodl_name1": "Jhon",
"aodl_name2": "Tiger",
"aodl_name3": "Jack",
...
}
How to do it?
Please let me know if you need more info about it.

You could either use Object.fromEntries
var aodl = { foo: 'foo', bar: 'bar' },
object = Object.fromEntries(Object
.entries(aodl)
.map(([key, value]) => ["aodl_" + key, value])
);
console.log(object);
Or map single objects and get a single object with Object.assign.
var aodl = { foo: 'foo', bar: 'bar' },
object = Object.assign(
{},
...Object.entries(aodl).map(([key, value]) => ({ ["aodl_" + key]: value }))
);
console.log(object);

You could use simply Object.assign()
const aodl = { name: 'John', name1: 'Wick' }
console.log(Object.assign({}, ...Object.entries(aodl).map(([key, value]) => ({['aodl_'+key]: value}))))

Related

Unstring an object property name javascript

I have an object similar to this:
const obj = {
id: 1,
name: {
"english-us": "John",
"english-uk": "John",
"italian-eu": "Giovanni",
},
};
I want to transfrorm every property name that is a string into a non-string one, like this:
const obj = {
id: 1,
name: {
english_us: "John",
english_uk: "John",
italian_eu: "Giovanni",
},
};
I can't modify the original object. I get it from an axios request.
You could use regex with stringify
let output = JSON.parse(JSON.stringify(obj).replace(/"(.*?)":.*?,?/g,
key=>key.replace(/\-/g, `_`)));
Output
console.log(JSON.stringify(output, null, 4));
/*
{
"id": 1,
"name": {
"english_us": "John",
"english_uk": "John",
"italian_eu": "Giovanni"
}
}*/
If you can copy the object, you could check this solution for declaring the attributes:
link
There are a few ways of achieving this. This example has a function that converts the key on every iteration of the name entries. A new names object is updated with these properties, and is later folded into a new object along with the existing properties of the original object.
const obj = {
id: 1,
name: {
"english-us": "John",
"english-uk": "John",
"italian-eu": "Giovanni",
},
};
const convert = (key) => key.replace('-', '_');
const updatedName = {};
for (const [key, value] of Object.entries(obj.name)) {
updatedName[convert(key)] = value;
}
const newObj = { ...obj, name: updatedName };
console.log(newObj);
You can convert object to JSON and convert back.
const obj = {
id: 1,
name: {
"english-us": "John",
"english-uk": "John",
"italian-eu": "Giovanni",
},
};
console.log(JSON.parse(JSON.stringify(obj)))
Two ways to clone the object and rename all keys from its name property
const obj = {
id: 1,
name: {
"english-us": "John",
"english-uk": "John",
"italian-eu": "Giovanni",
},
};
// clone obj
const myObj = window.structuredClone ?
structuredClone(obj) : JSON.parse(JSON.stringify(obj));
// rename all keys in myObj.name
Object.keys(myObj.name).forEach(key => {
myObj.name[key.replace(/\-/g, `_`)] = myObj.name[key];
delete myObj.name[key];
});
console.log(myObj.name.english_us);
// obj is untouched
console.log(obj.name[`english-us`]);
// myObj.name[`english-us`] does not exist
console.log(myObj.name[`english-us`]);
// alternative: clone and rename in one go
const myObjClone = {
...obj,
name: Object.fromEntries(
Object.entries(obj.name)
.reduce( (acc, [k, v]) =>
[ ...acc, [ k.replace(/\-/g, `_`), v ] ] , [] ) )
};
console.log(myObjClone.name.italian_eu);
// obj is untouched
console.log(obj.name[`italian-eu`]);
// myObjClone.name[`italian-eu`] does not exist
console.log(myObjClone.name[`italian-eu`]);

Create objects from main key and value from nested object

I'll keep it simple. Suppose I have an object like this:
let myObj = {
name:{
value: "John",
type: "contains"
},
age:{
value: "5",
type: "contains"
}
}
how can I create a new object that contains the main key but the value is just the value of its nested object, as follows:
let myNewObj = {
name: "John",
age: "5"
}
Thanks in advance.
If you just want to extract the value key for each object, you can do something like this:
let myObj = {
name:{
value: "John",
type: "contains"
},
age:{
value: "5",
type: "contains"
}
}
let newObj = {}
for (const key in myObj) {
newObj[key] = myObj[key].value;
}
console.log(newObj);
// {
// age: "5",
// name: "John"
// }
Convert the object to its entries array and map through it to return [key,value]
Then convert to a new object using Object.fromEntries
let myObj = {
name:{
value: "John",
type: "contains"
},
age:{
value: "5",
type: "contains"
}
}
let myNewObj = Object.fromEntries(Object.entries(myObj).map(([key,{value}])=>[key,value]))
console.log(myNewObj)
In general, to be able to transform all the values of an object's properties according to a mapping function, you can use Object.entries to make an array of [key, value] arrays for each property, and then use Object.fromEntries to reconstitute an object from those arrays. You can provide a generic transformation function in the middle of that operation like this:
const transformValues = (obj, transform) =>
Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, transform(value)]));
The transform function you need in your specific case will take the property value (which is an object) and just return its value property. Like this: ({ value }) => value (This is pretty easy with destructuring.)
let myObj = {
name: {
value: "John",
type: "contains"
},
age: {
value: "5",
type: "contains"
}
}
const transformValues = (obj, transform) =>
Object.fromEntries(Object.entries(obj).map(([key, value]) => [key, transform(value)]));
const result = transformValues(myObj, ({ value }) => value);
console.log(result);

How to map or assign an entry to an array-item based on some of this item's conditions?

I have array of objects,
if the name is xx then push xitems to that object and
if the name is yy then push yitems to that object
Below is the code tried , and also should not use spread operator
const result = [];
var ss=arrobj.forEach(function(e){
if(e.name === 'xx'){
result.push({id: e.id, name: e.name, country:e.country, others: xitems})
}
if(e.name === 'yy'){
result.push({id: e.id, name: e.name, country:e.country, others: yitems})
}
return result;
});
var arrobj =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
]
xitems =[
{title: "Finance", valid: true}
]
yitems =[
{title: "Sales", valid: true}
]
Expected Output
[
{id:1, name: "xx", country: "IN",
others:[
{title: "Finance", valid: true}
]
},
{id:2, name: "yy", country: "MY",
others: [
{title: "Sales", valid: true}
]
},
]
You should use .map for this.
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj.map((item) => {
if (item.name === "xx") {
item.others = xitems;
} else if (item.name === "yy") {
item.others = yitems;
}
return item;
});
console.log(result);
Your code works, the only issue that I identified are.
There is no need to assign var ss with arrobj.forEach. Because Array.forEach donot return a value.
No need of return result; inside Array.forEach.
Also as an improvement you can simply assign the object with key others like Object.assign({}, e, { others: xitems }), rather than returning individual key value.
Working Fiddle
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
]
const xitems = [
{ title: "Finance", valid: true }
]
const yitems = [
{ title: "Sales", valid: true }
]
const result = [];
arrobj.forEach(function (e) {
if (e.name === 'xx') {
result.push(Object.assign({}, e, { others: xitems }))
}
if (e.name === 'yy') {
result.push(Object.assign({}, e, { others: yitems }))
}
});
console.log(result)
Variables are references to an object that has a value, variables do not store values. It is pointless to try to use a variable in that manner unless you have specific parameters. If you insist on a condition then you need to identify xitems and yitems by the objects values and/or properties or by the order they came in. If you have dynamic data how would you know what xitems or yitems really is?
The example below has been made reusable as long as you meet these requirements:
Must have an array of objects as a primary parameter.
Must have at least one array of objects for each object in the primary array. If there's more the rest will be ignored.
The secondary array of objects must be in the order you want then to end up as.
The second parameter is a rest parameter (not a spread operator, although I have no idea why OP does not want to use it). This will allow us to stuff in as many object arrays as we want.
const distOther = (main, ...oAs) => {...
Next we create an array of pairs from all of the secondary arrays
let others = oAs.map(sub => ['others', sub]);
// [['others', [{...}]], [['others', [{...}]], ...]
Then we turn our attention to the primary array. We'll work our way from the inside out. .map() each object as an array of pairs by Object.entries():
main.map((obj, idx) =>
// ...
Object.entries(obj)
// ...
// [{A: 1, B: 2}, {...}] => [[['A', 1], ['B', 2]], [[...], [...]]]
Then .concat() (a spead operator would be more succinct) each array of pairs with that of the secondary array of pairs corresponding to the current index (you'll need to wrap each secondary array in another array, so the return will level off correctly):
// main.map((obj, idx) =>
// ...
// Object.entries(obj)
.concat([others[idx]])));
// [[['A', 1], ['B', 2], ['others', [{...}]], [[...], [...], ['others', [{...}]]]
Finally we'll use Object.fromEntries() to convert each array of pairs into an object.
// main.map((obj, idx) =>
Object.fromEntries(
// Object.entries(obj)
// .concat([others[idx]])));
// [{'A': 1, 'B': 2, 'others': [{...}]},...]
const objArr =[
{id:1, name: "xx", country: "IN"},
{id:2, name: "yy", country: "MY"},
];
const x =[
{title: "Finance", valid: true}
]
const y =[
{title: "Sales", valid: true}
]
const distOther = (main, ...oAs) => {
let others = oAs.map(sub => ['others', sub]);
return main.map((obj, idx) =>
Object.fromEntries(
Object.entries(obj)
.concat([others[idx]])));
};
console.log(distOther(objArr, x, y));
I would choose a map based approach as well but without the if clauses which explicitly check for expected values of the mapped item's name property.
The approach instead utilizes map's 2nd thisArg parameter which gets applied as the mapper functions this context. Such an additional object can be provided as a map/index of custom key value pairs where key equals a mapped item's name.
Thus the mapper implementation features generic code, and due to the this binding it will be provided as function statement which makes it also re-usable and, if properly named, readable / comprehensible / maintainable too.
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item,
{ others: index[item.name] ?? [] },
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
As one can see, the above implementation via Object.assign creates a new object from each mapped arrobj item. Thus the original item-references remains untouched / non mutated. It does not apply for the items of xitems and yitems since both array references are directly assigned each to its newly created others property. The above log does reflect this.
In case the goal was an entirely reference free data structure one needs to slightly change the Object.assign part of assignBoundNamedValueAsOthers ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// create new object and assign, according to
// `item.name`, bound named value as `others`.
return Object.assign(
{},
item, {
others: (index[item.name] ?? [])
// dereference the `others` items as well.
.map(othersItem =>
Object.assign({}, othersItem)
)
},
);
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
const result = arrobj
.map(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
result,
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }
In case the OP does not need to care about immutability, the entire process then changes from a map task to a forEach task, where assignBoundNamedValueAsOthers does directly change/mutate each currently processed item of arrobj, thus forEach does not return any data but always the undefined value ...
function assignBoundNamedValueAsOthers(item) {
// the bound key value pairs.
const index = this;
// mutate the original reference of the currently
// processed `item` by directly assigning, according
// to `item.name`, the bound named value as `others`.
Object.assign(
item,
{ others: index[item.name] ?? [] },
);
// no explicit return value due to
// going to be used as a `forEach` task.
}
const arrobj = [
{ id: 1, name: "xx", country: "IN" },
{ id: 2, name: "yy", country: "MY" },
];
const xitems = [{ title: "Finance", valid: true }];
const yitems = [{ title: "Sales", valid: true }];
// mutates each item of `arrobj`.
arrobj.forEach(assignBoundNamedValueAsOthers, {
// each `key` equals an expected item's `name`.
xx: xitems,
yy: yitems,
});
console.log({
arrobj,
xitems,
yitems,
});
.as-console-wrapper { min-height: 100%!important; top: 0; }

Merging two Javascript objects with similar keys

I need to merge two objects(obj1, obj2), that happen to share similar keys.
obj1 = {
0:{"Example1": "Example1"},
1:{"Example1": "Example1"},
2:{"Example1": "Example1"}
}
obj2 = {
0:{"Example2": "Example2"},
1:{"Example2": "Example2"},
2:{"Example2": "Example2"}
}
Expected result:
obj3 = {
0:{"Example1": "Example1"},
1:{"Example1": "Example1"},
2:{"Example1": "Example1"},
3:{"Example2": "Example2"},
4:{"Example2": "Example2"},
5:{"Example2": "Example2"},
}
Usual approach when merging two objects:
const obj3 = Object.assign({}, obj1, obj2);
Problem: They do share many keys, as such, in obj3, only the contents of obj2 are going to be found.
My approach:
let obj3= Object.assign({}, obj1);
for(let i=0; i<obj2.length; i++) {
obj3[obj3.length + i] = obj2[i];
}
Question: Is there, another more elegant, pre-defined way of merging two objects with similar keys?
Although I still think obj1 and obj2 should be arrays...
const obj1 = {
0:{"Example1": "Example1"},
1:{"Example1": "Example1"},
2:{"Example1": "Example1"}
};
const obj2 = {
0:{"Example2": "Example2"},
1:{"Example2": "Example2"},
2:{"Example2": "Example2"}
}
const result = Object.fromEntries(
Object.values(obj1) // get the values of the first object
.concat(Object.values(obj2)) // get the values of the second object and add them to the values of the first
.map((value, index) => [ index, value ]) // re-index them
// or if you need actual copies of the "inner" objects
/*
.map((value, index) => [
index,
Object.assign({}, value)
])
*/
);
console.log(result);
Is this "more elegant". Maybe...
The objects in your code are key-value pairs rather than a simple list (array).
From the looks of it there are only two possible scenarios:
Your objects have a meaningful, unique key associated to them (for example, this very question on stackoverflow has key 69316153 – look at the URL bar). In this case, you really can't merge the two as they have conflicting keys. Think if there was another question on this website with the same ID as this one!
The keys are not meaningful and you're happy with the same object being re-assigned a different key. In this case the correct data structure to use is arrays (obj1 = [{"Example": "..."}, {"Example": "..."}]).
If the latter is your situation, this code will work:
const obj3 = Object.values(obj1).concat(Object.values(obj2))
Object.values(obj) returns an array of values, discarding all of the keys.
Let's say we have:
const obj1 = {
1: { Name: "Apple" },
2: { Name: "Watermelon" },
};
const obj2 = {
2: { Name: "Pear" },
5: { Name: "Tomato" }
};
Object.values(obj1) will return [{ Name: "Apple" }, { Name: "Watermelon" }], while Object.values(obj2) will return [{ Name: "Pear" }, { Name: "Tomato" }].
With const obj3 = Object.values(obj1).concat(Object.values(obj2)) you will end up with:
obj3 = [
{ Name: "Apple" },
{ Name: "Watermelon" },
{ Name: "Pear" },
{ Name: "Tomato" }
];
Because you have key-value maps and not arrays, you can't just combine the objects. Your only way would be to iterate through all the keys and add them to the final result.
E.g. something along the lines:
const obj1 = {
0:{"Example1": "Example1"},
1:{"Example1": "Example1"},
2:{"Example1": "Example1"}
};
const obj2 = {
0:{"Example2": "Example2"},
1:{"Example2": "Example2"},
2:{"Example2": "Example2"}
};
function merge(...args) {
return Object.fromEntries( // Create entries
args // From all arguments
.flatMap(o => Object.values(o)) // Get values (discard keys)
.map((element, index) => [ index, element ]) // Remap them
);
}
console.log(merge(obj1, obj2));
// Will output
// {
// 0: { Example1: "Example1" },
// 1: { Example1: "Example1" },
// 2: { Example1: "Example1" },
// 3: { Example2: "Example2" },
// 4: { Example2: "Example2" },
// 5: { Example2: "Example2" }
// }

How to remove duplicates with extra keys from an array

I have two arrays:
const a1=[
{
a:{ name: "first" }
},
{
b:{ name: "second" }
},
{
c:{ name: "third" }
},
{
d:{ name: "fourth" }
}
]
const a2=[
{
a:{ name: "first", shelf: "read" }
},
{
b:{ name: "second", shelf: "current" }
}
]
I need to check if contents of a1 is in a2 and if it exists replace it in a1 (basically shelf name is missing in a1. I need to update that in a1).
My end result should look like:
[
{
a:{ name: "first", shelf: "read" }
},
{
b:{ name: "second", shelf: "current" }
}
{
c:{ name: "third" }
},
{
d:{ name: "fourth" }
}
]
I have tried something like
const x = a1.map( ele => {
a2.map( e => {
if( e.name === ele.name ) return ele
else return ({ ...ele, shelf: 'none' })
})
return ele;
})
But since I don't have access to the inner maps return value I get the original array back. One way I though of doing this was to concatenate both arrays and use reduce the array by checking the shelf name using javascript's reduce method. Can someone help me with a better method.
I would go by first creating an Auxiliary object for "a2" and when I am looping over a1, in each loop I would check the existence of the current key in the auxiliary object.
Having an Auxiliary Object save you unnecessary loops, you only traverse both the arrays only once.
const a1 = [{a: {name: "first"}}, {b: {name: "second"}}, {c: {name: "third"}}, {d: {name: "fourth"}}];
const a2 = [{a: {name: "first", shelf: "read"}}, {b: {name: "second",shelf: "current"}}];
const dict = a2.reduce((acc, ob) => {
const [k, v] = Object.entries(ob)[0];
acc[k] = v;
return acc;
}, {});
const newA1 = a1.map((ob) => {
const [k, v] = Object.entries(ob)[0];
if (dict[k]) {
Object.assign(v, dict[k]);
}
return {[k]: v};
});
console.log(newA1)
This should do the job in a concise way:
a1.map((it)=> {
const key = Object.keys(it)[0];
const a2item = a2.find( (it2) => Object.keys(it2)[0]===key );
if(a2item) {
Object.assign(it[key], a2item[key]);
}
return it;
});
Please note that the elements of the original a1 array are modified.

Categories

Resources