React - How to convert a nested object into a array - javascript

I have the following object that I would like to convert it into an array of object and each object from the array to have the key: value[0].
object:
const obj = {
comedy: ['book1', 'book2'],
action: ['book3', 'book4'],
drama: ['book5'],
}
output
const arr = [
{comedy: 'book1'},
{comedy: 'book2'},
{action: 'book3'},
{action: 'book4'},
{drama: 'book5'},
]
So far I have tried solving this with loops and using Object.entries. But I do not get the output I need.
let result = [];
for(const [key1, value1] of Object.entries(arr)) {
for (const [key2, value2] of Object.entries(value1)) {
if(result[key2]) {
result[key2] [key1] = value2
} else {
result[key2] = {[key1]: value2}
}
}
}
console.log(result)
I have also tried to loop recalling the function inside itself. (I have found this search for the answer). But it will get stucked in a infinite loop.
const result = [];
const getArray = (obj) => {
if (!obj) return;
const {keys, ...rest} = obj;
result.push({...rest});
getArray(keys);
}
console.log('here', getArray(arr));

You could use a reduce over the entries of obj, adding objects to the accumulator for each entry in the array value:
const obj = {
comedy: ['book1', 'book2'],
action: ['book3', 'book4'],
drama: ['book5'],
}
const arr = Object.entries(obj)
.reduce((acc, [k, v]) => acc.concat(v.map(b => ({ [k] : b }))),
[]
)
console.log(arr)

Try this
function nestedObjectIntoArray(obj) {
const arr = [];
for (const key in obj) {
for (const value of obj[key]) {
const obj = {};
obj[key] = value;
arr.push(obj);
}
}
return arr;
}
const obj = {
comedy: ["book1", "book2"],
action: ["book3", "book4"],
drama: ["book5"],
};
console.log(nestedObjectIntoArray(obj));

const obj = {
comedy: ['book1', 'book2'],
action: ['book3', 'book4'],
drama: ['book5'],
}
const result = Object
.keys(obj)
.reduce((acc, key) =>
[...acc, ...obj[key]
.map((value) => ({[key]: value}))],
[]
)
console.log(result)

We can also achieve this by just using Array.forEach() method.
Live Demo :
// Input object
const obj = {
comedy: ['book1', 'book2'],
action: ['book3', 'book4'],
drama: ['book5'],
};
// Declare a variable to store the final result.
const arr = [];
// Iterate the input object based on the keys and build the final object.
Object.keys(obj).forEach(key => {
obj[key].forEach(item => {
arr.push({ [key]: item })
})
});
// Result
console.log(arr);

we can achieve this way too
const obj = {
comedy: ['book1', 'book2'],
action: ['book3', 'book4'],
drama: ['book5'],
}
const fun = (ar, temp)=>{
for(x in ar){
ar[x].map((e, i)=> {
var data = {[x] : e}
temp.push(data)
})}
return temp
}
console.log(fun(obj , []))

Related

How to get values from array of objects in javascript

I have an array of object from which I am trying to get values using map operator but I am getting the whole json objects all I want is just array of values.
Below is my code:
const obj = [
{
a: {
b: 'Paul',
}
},
{
c: 'Byeeee',
}
];
obj.map((val) => console.log(val));
what I am getting is
{ a: { b: 'Paul' } }
{ c: 'Byeeee' }
What I want is:
['Paul','Byeeee']
Someone let me know how can I get the desired output.
You can do this recursively. You can first start off by grabbing the values of your object, and then loop through those using .flatMap(). If you encounter a value that is an object, you can recursively grab the values of that object by recalling your function. Otherwise, you can return the value. The advantage of using .flatMap() here is that when the recursive call returns an array, we don't end up with inner arrays, but rather the array gets flattened into one resulting array:
const obj = [{ a: { b: 'Paul', } }, { c: 'Byeeee', } ];
const getValues = (obj) => {
return Object.values(obj).flatMap(val => Object(val) === val ? getValues(val) : val);
}
console.log(getValues(obj));
you can use the following solution.
const data = [{ a: { b: 'Paul' } }, { c: 'Byeeee' }];
const flatObjectValues = (obj, result) => {
// recursive function to get object values
const objValues = Object.values(obj);
if (objValues?.length > 0) {
objValues.map((v) => {
if (typeof v === 'object' && !Array.isArray(v)) {
flatObjectValues(v, result);
} else {
result.push(v);
}
return v;
});
}
};
const updatedData = [];
data.map((x) => flatObjectValues(x, updatedData));
console.log('updatedData: ', updatedData);
You can use recursion with array.reduce, like fellowing.
function getAllValues(objuct) {
return objuct.reduce((acc, curr) => {
if (typeof curr === 'object') {
return [...acc, ...getAllValues(Object.values(curr))];
}
return [...acc, curr];
}, []);
}
A recursive solution could be:
const arr = [{a: {b: "Paul",},},{c: "Byeeee",},];
const flatArrOfObjects = (arr) => {
const values = [];
for (const i in arr) flatObj(arr[i], values);
return values;
};
const flatObj = (obj, result) => {
for (const [key, value] of Object.entries(obj)) {
if (typeof value === "object") flatObj(value, result);
else result.push(value);
}
};
console.log(flatArrOfObjects(arr));

how to make an array of strings into a key value pair object, making the value an array?

I've got an array of strings like so:
[
"hl7_file_type_1.msgtype",
"hl7_file_type_1.filename",
"hl7_file_type_2.msgtype",
"hl7_file_type_2.filename",
"hl7_file_type_3.msgtype",
"hl7_file_type_3.filename"
]
I am trying to convert this into a key value pair object like so (expected result):
{
"hl7_file_type_1": ["msgtype","filename"],
"hl7_file_type_2": ["msgtype","filename"],
"hl7_file_type_3": ["msgtype","filename"],
}
Here is how I am attempting this:
let tmp = {};
for (let i = 0; i < this.regexArray.length; i++){
let split = this.regexArray[i].split('.');
tmp[split[0].trim()] = split[1].trim();
}
console.log('Key Value')
console.log(tmp);
Here is what is returning:
{
"hl7_file_type_1": "filename",
"hl7_file_type_2": "filename",
"hl7_file_type_3": "filename"
}
How can I change my function to return the expected result like mentioned above
You can easily achieve this using reduce
const arr = [
"hl7_file_type_1.msgtype",
"hl7_file_type_1.filename",
"hl7_file_type_2.msgtype",
"hl7_file_type_2.filename",
"hl7_file_type_3.msgtype",
"hl7_file_type_3.filename",
];
const result = arr.reduce((acc, curr) => {
const [prop, type] = curr.split(".");
if (!acc[prop]) acc[prop] = [type];
else acc[prop].push(type);
return acc;
}, {});
console.log(result);
A bit of mapping and reducing should do it
const input = [
"hl7_file_type_1.msgtype",
"hl7_file_type_1.filename",
"hl7_file_type_2.msgtype",
"hl7_file_type_2.filename",
"hl7_file_type_3.msgtype",
"hl7_file_type_3.filename"
]
const result = input.map(i => i.split(".")).reduce( (acc,[key,value]) => {
return {
...acc,
[key]: [...(acc[key] || []), value]
}
},{});
console.log(result);
Simply map and then reduce.
const data = [
"hl7_file_type_1.msgtype",
"hl7_file_type_1.filename",
"hl7_file_type_2.msgtype",
"hl7_file_type_2.filename",
"hl7_file_type_3.msgtype",
"hl7_file_type_3.filename",
];
const res = data
.map((d) => d.split("."))
.reduce((r, [k, v]) => ((r[k] ??= []), r[k].push(v), r), {});
console.log(res);

Access javascript object value by array

I have an object like: const obj = { 'abc': {'def': 1 } } and I have an array like const arr = ['abc', 'def'] How can I access obj.abc.def property of my object with the array?
Obviously, obj[arr] doesn't work, also obj[arr.join('.') doesn't work.
What I want to do is:
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const value = obj[arr] // crash
// value should contain 1
You could take a dynamic approach and reduce the keys and take a default object, if a part is not accessable.
const
getValue = (object, keys) => keys.reduce((o, k) => (o || {})[k], object),
obj = { abc: { def: 1 } },
arr = ['abc', 'def'],
value = getValue(obj, arr);
console.log(value);
console.log(getValue(obj, ['foo', 'bar']));
The base is
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
console.log(obj[arr[0]][arr[1]]);
or if you need to do it with a function...
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
function access(obj, arr) {
return arr.reduce((o, key) => o[key], obj);
}
console.log(access(obj, arr));
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
var value = obj;
for(let key of arr){
value = value[key];
}
console.log(value);
You can access the array property by index only. so arr[0] will work.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const value = obj[arr[0]][arr[1]]
console.log(value)
or you can run the loop over it.
const obj = { 'abc': {'def' : {'ghi': 1 } } };
const arr = ['abc', 'def', 'ghi'];
let ans = null;
for (let i=0; i<arr.length; i++) {
if(i==0) {
ans = obj[arr[0]];
}
else {
ans = ans[arr[i]];
}
}
console.log(ans)
You can use Array#reduce for a dynamic array.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def']
const res = arr.reduce((o,prop)=>o[prop], obj);
console.log(res);
If you do not want errors to be thrown on properties that do not exist, you can use the optional chaining operator.
const obj = { 'abc': {'def': 1 } }
const arr = ['abc', 'def', 'notdefined', 'notdefined2']
const res = arr.reduce((o,prop)=>o?.[prop], obj);
console.log(res);
What you try to do is somewhat called object value "get by path", some library have support this and for example ramda is a production-ready library for that, you should not try to reinvent the wheel (practice is okay)
In your context, ramda's path method could help you achieve to the case of arbitrary array of properties
const obj = {
'abc': {
'def': 1,
'ghi': {
'jkl': 10
}
}
}
console.log(R.path(['abc', 'def'], obj))
console.log(R.path(['abc', 'ghi'], obj))
console.log(R.path(['abc', 'ghi', 'jkl'], obj))
console.log(R.path(['abc', 'ghi', 'jkl', 'mno'], obj))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

Lodash findKey() method

As a part of a challenge I need to implement the .findKey() method myself. Below is the solution proposition, however, I get an error "predicate is not a function".
const _ = {
findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) {
return key;
};
};
undefined
return undefined;
}
};
Can anyone help?
function findKey(object, predicate) {
for (let key in object) {
let value = object[key];
let predicateReturnValue = predicate(value);
if (predicateReturnValue) { // just take the value
return key; // return key
}
}
}
const isEqual = a => b => a === b
const object = { a: 'Apple', b: 'Beer', c: 'Cake' }
alert(findKey(object, isEqual('Apple')));
alert(findKey(object, isEqual('Cakes')));

Change object keys from underscore format to camelCase format

I'm trying to get this:
const obj = {
keyFirst: 'firstVal',
keySecond: 'secondVal',
};
from this:
const obj = {
key_first: 'firstVal',
key_second: 'secondVal',
};
...so to change underscore key format to camelCase format.
I tried to achieve it by using reduce function:
const renameKeys = obj => Object
.keys(obj)
.reduce((acc, key) => {
const modifiedKey = key.replace(/_([a-z])/g, function f(g) {
return g[1].toUpperCase();
});
return ({
...acc,
...{ [modifiedKey]: obj[key] },
}, {});
});
console.log(renameKeys(obj));
But this won't work and return empty objects. How can I change it to achieve my goal?
The problem is
return ({
...acc,
...{ [modifiedKey]: obj[key] },
}, {});
You're unintentionally using the comma operator - although the new object is evaluated, the whole expression inside the parentheses evaluates to the final value in the comma-separated list, which is the empty object, which becomes the accumulator on the next iteration.
Don't use the comma operator in the return, and pass {} as a second argument to reduce instead:
const obj = {
key_first: 'firstVal',
key_second: 'secondVal',
};
const renameKeys = obj => Object
.keys(obj)
.reduce((acc, key) => {
const modifiedKey = key.replace(/_([a-z])/g, function f(g) {
return g[1].toUpperCase();
});
return ({
...acc,
...{ [modifiedKey]: obj[key] },
});
}, {});
console.log(renameKeys(obj));
Also, rather than using Object.keys, you might consider Object.entries instead, because [modifiedKey]: value is probably a bit clearer than [modifiedKey]: obj[key]:
const obj = {
key_first: 'firstVal',
key_second: 'secondVal',
};
const renameKeys = obj => Object
.entries(obj)
.reduce((acc, [key, val]) => {
const modifiedKey = key.replace(/_([a-z])/g, g => g[1].toUpperCase());
return ({
...acc,
...{ [modifiedKey]: val },
});
}, {});
console.log(renameKeys(obj));
You can split the key name by group and use $1 & $2 where these represent group
const obj = {
keyFirst: 'firstVal',
keySecond: 'secondVal',
};
let newObj = {}
for (let keys in obj) {
newObj[keys.replace(/([a-z0-9])([A-Z])/g, '$1_$2').toLowerCase()] = obj[keys]
}
console.log(newObj)

Categories

Resources