Map an object array with unknown length and unknown key names - javascript

Here are some object arrays:
1. [{id:'1', code:'somecode', desc:'this is the description'}, {...}, {...}]
2. [{fname:'name', lname:'last name', address:'my address', email:'my#email.com'}, {...}, {...}]
What I need to do is create a function where I pass an array and map their object keys to generic keys so they become like this:
1. [{key1:'1', key2:'somecode', key3:'this is the description'}, {...}, {...}]
2. [{key1:'name', key2:'last name', key3:'my address', key4:'my#email.com'}, {...}, {...}]
When I do this
let keys: string[] = Object.keys(this.options[0])
this.replacedItems = this.options.map(item => {
return{
key1: item[keys[0]],
key2: item[keys[1]],
key3: item[keys[2]],
}
});
it works fine, but since the object's properties number is not fixed, I tried this
let keys: string[] = Object.keys(this.options[0])
this.replacedItems = this.options.map(item => {
let i=0;
keys.forEach(key=>{
let newKey = 'key'+i;
i++
return { newKey: item[key] }
});
});
which rerurns an array of undefined...
What am I doing wrong?

Take the second parameter of .map to get the current index you're iterating over, and concatenate it with 'key'. You can also use Object.values instead of Object.keys to get the values immediately (since you're not actually using the original keys):
const options = [{id:'1', code:'somecode', desc:'this is the description'}];
const replacedItems = options.map(obj => Object.fromEntries(
Object.values(obj).map((val, i) => ['key' + (i + 1), val])
));
console.log(replacedItems);

Related

How can we create OBJ property with the same name from array values?

Hello I'm trying to create an object that includes under the same property name a bunch of array values,
This what I'm trying
const quiz = [
{question: 'Who is the main character of DBZ',
options: ['Vegetta','Gohan','Goku']}
]
const newObj = {
options: []
}
quiz.forEach((item)=>{
item.options.forEach((item, index)=>{
newObj.options[`name${index}`] = item
})
})
expected value =
newObj = {
options: [{name: 'Vegetta'},{name:'Gohan'},{name:'Goku'}]
}
actual value received =
newObj = {
{ options: [ name0: 'Vegetta', name1: 'Gohan', name2: 'Goku' ] }}
Thanks in advance!
As you've noticed, newObj.options[`name${index}`] = item creates a new key on your options array, and sets that to item. You instead want to push an object of the form {name: item} into your array. There are a few ways you could go about this, one way is to use .push() like so:
quiz.forEach((item)=>{
item.options.forEach((item)=>{
newObj.options.push({name: item});
})
});
while not as common, you can also use set the current index of options, which is slightly different to the above example, as it will maintain the same index, which can be important if quiz is a sparse array that you want to keep the same indexing of on options:
quiz.forEach((item)=>{
item.options.forEach((item, index)=>{
newObj.options[index] = {name: item};
})
});
Example of the difference:
const arr = [1, 2,,,5]; // sparse array
const pushRes = [];
const indxRes = [];
arr.forEach(n => pushRes.push(n));
arr.forEach((n, i) => indxRes[i] = n);
console.log("Push result", pushRes);
console.log("Index result", indxRes);
For a different approach, you also have the option of using something like .flatMap() and .map() to create your options array, which you can use to create newObj:
const quiz = [
{question: 'Who is the main character of DBZ',
options: ['Vegetta','Gohan','Goku']}
];
const options = quiz.flatMap(({options}) => options.map(name => ({name})));
const newObj = {options};
console.log(newObj);

Convery JS Object to array - keep key & value

I am trying to convert an object (updatedConfig) to an array (configArray), while maintaining the same structure (and avoid further nesting).
I have tried declaring a new array const and using Object.entries to push the keys & values.
I am able to get the keys but am having trouble figuring out how to achieve the nesting of array.
const configArray = [];
Object.entries(updatedConfig).forEach(([key, value]) => {
configArray.push(key);
})
Here is the object in question:
You can try something like this using Object.entries and Array.map
const configObject = {
key1: 'value',
key2: 1,
key3: [1, 2, 3]
}
const configArray = Object.entries(configObject).map(([key, value]) => ({key, value}))
console.log(configArray)

Returning all key:value pairs from object array that key includes underscore in javascript

I have rows that contain data in form like this:
{
id:"id",
param:"street1",
param:"street2",
param_eu:"street",
param_ru:"street",
},
{
id:"id2",
param:"street1",
param:"street2",
param_fr:"street",
param_cz:"street",
},
I would like to pick only pairs that contain "_" and only keep the country as key name, like this:
{
eu:"street",
ru:"street"
},
{
fr:"street",
cz:"street"
},
Managed to get it done with multiple inner for loops but that is huge. Any better solutions?
You can first use .map() on your array to map each object to a new object. The new objects are created using Object.fromEntries(), Object.entries(), .filter() and .map(). You can use these methods as follows:
Use Object.entries() to obtain an array of [[key, value],...] pairs from your object.
On the above key-value pair array, use .filter() to obtain only the keys that contain an underscore in them by checking if the key includes an underscore "_"
Once you have filtered your array, use .map() on your filtered key-value array to map each inner array (ie: [key, value]) to a new array, where everything to the left of the underscore is removed. To do this, you can split your key using "_" to form an array of two parts - the "param" & the alpha country code. You can use .pop() to obtain the last string in your array of parts (ie: the alpha country code)
Wrap this filtered/mapped array of key-value pairs in a call to Object.fromEntries(). Since this takes an array of [[key, value], ...] pairs, it will be able to build an object for you, where each inner [key, value] array is converted into a {key: value, ...} in the resulting object.
See example below:
const arr = [{ id: "id", param: "street1", param: "street2", param_eu: "street", param_ru: "street", }, { id: "id2", param: "street1", param: "street2", param_fr: "street", param_cz: "street", } ];
const res = arr.map(
obj => Object.fromEntries(
Object.entries(obj).filter(
([key]) => key.includes("_")
).map(([key, val])=> [key.split("_").pop(), val])
)
);
console.log(res);
You can iterate over the list, and every time, reduce the object properties:
const data = [
{ id:"id", param:"street1", param:"street2", param_eu:"street", param_ru:"street" },
{ id:"id2", param:"street1", param:"street2", param_fr:"street", param_cz:"street" }
];
// iterate over objects
const res = data.reduce((countries, item) => {
// reduce object properties
const itemWithCountries = Object.entries(item)
.reduce((acc, [key, value]) => {
if(key.includes('_')) acc[key.split('_').pop()] = value;
return acc;
}, {});
// push reduced object
if(Object.keys(itemWithCountries).length > 0) countries.push(itemWithCountries);
return countries;
}, []);
console.log(res);
You could map new object by getting all entries from the objects, get the one you want and build object from the entries as new objects.
const
array = [{ id: "id", param: "street1", param: "street2", param_eu: "street", param_ru: "street" }, { id: "id2", param: "street1", param: "street2", param_fr: "street", param_cz: "street" }],
result = array.map(object => Object.fromEntries(Object
.entries(object)
.filter(([key]) => key.includes('_'))
));
console.log(result);

How to create object from another without undefined properties [duplicate]

This question already has answers here:
Remove blank attributes from an Object in Javascript
(53 answers)
Closed 2 years ago.
Is there a better way to accomplish this in Javascript?
const data: any = {};
if (values.email) data.email = values.email;
if (values.password) data.password = values.password;
if (values.username) data.username = values.username;
I don't want the data object to have the properties for the undefined or falsy values.
You could put the potential properties in an array and then .filter() out any which values[prop] has a fasly value for. Then you can .map() each key to an array of [key, value] pairs, and use Object.fromEntries() to build the data object for you:
const values = {
email: 'abc',
username: 'xyz'
};
const props = ['email', 'password', 'username'];
const data = Object.fromEntries(
props.filter(prop => values[prop]).map(prop => [prop, values[prop]])
);
console.log(data);
If you can't support Object.fromEntries(), you could consider using Object.assign(), and then mapping to an array of objects which you then spread into Object.assign():
const values = {
email: 'abc',
username: 'xyz'
};
const props = ['email', 'password', 'username'];
const data = Object.assign({},
...props.filter(prop => values[prop]).map(prop => ({[prop]: values[prop]}))
);
console.log(data);
You can do something along these lines:
const obj1 = {
prop1: true,
prop2: false,
prop3: 4,
}
const obj2 = Object.entries(obj1).reduce((result, [key, value]) => {
if (value) {
result[key] = value
}
return result
}, {})
console.log(obj2)
This simple function will do it, if you want to copy over all properties that don't have a false-y value. If you only want a fixed list, look at the answer from Nick Parsons.
const copyNonNil = (obj) =>
Object .fromEntries (Object .entries (obj) .filter(([k, v]) => v))
const values = {
email: 'foo#bar.baz',
username: 'foobar',
password: '',
another: false
}
console .log (copyNonNil (values))
It's easy to shim Object .fromEntries if you don't have it available. See the answer from theDude, which uses a reduce that serves in the same role.
You could use Object.entries to iterate over the properties of values and perform the true/false check in that to make this more flexible:
for(const [key, value] of Object.entries(values)){
if(values[key]) data[key] = value;
}
This would give you only the truthy values in data for a values object of any size.

Get array of keys based on values from another array

Say I have an array of objects that looks like this
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
How would I iterate though this to return a new array of true values that looks like this:
let newArray = ['item1', 'item3']
I found this function but it only returns single items:
function findKey(map, term) {
var found = [];
for(var property in map) {
if(map.hasOwnProperty(property)) {
for(var key in map[property]) {
if(map[property].hasOwnProperty(key) && key === term) {
found.push(property);
}
}
}
}
return found;
}
Assuming myArray always contains objects with only 1 property.
let newArray = myArray
.map(item => Object.entries(item)[0])
.filter(([key, value]) => value)
.map(([key, value]) => key)
You could access the first key of each array item via Object.keys(), and use this to filter items with a true value for that first key, and then complete the process with a call to map() to transform the item to a value based on the same "first key" technique:
let myArray = [
{item1: true},
{item2: false},
{item3: true},
{item4: false}
]
let result = myArray
.filter(item => item[ Object.keys(item)[0] ] === true)
.map(item => Object.keys(item)[0])
console.log(result)
Use the function reduce to build the desired output. The handler of the function reduce will get the keys and check for each value === true.
This approach checks for the whole set of keys within an object. Further, this way you only use one loop.
let myArray = [{item1: true},{item2: false},{item3: true},{item4: false}],
result = myArray.reduce((a, c) => a.concat(Object.keys(c).filter(k => c[k] === true)), []);
console.log(result);
Something much optimized than the accepted answer would look like this:
const arr = [
{ item1: true },
{ item2: false },
{ item3: true },
{ item4: false }
]
const result = [];
const len = arr.length;
for (let i = 0; i < len; ++i) {
const obj = arr[i];
const key = Object.keys(obj)[0];
if(obj[key]) {
result.push(key);
}
}
console.log(result);
There is only one loop over the array, instead of map and filter which ends up looping twice.
Shortest
let newArray = myArray.map( x=>Object.keys(x)[0] ).filter( (k,i)=>myArray[i][k] );
In above solution first we use: map which works as for-loop to get array of keys (using Object.keys) ["item1", "item2", "item3", "item4"]. Then we filter that array by choose only those keys for which original array object has true. e.g myArray[0]["item1"] -> true (we use fact that filter funtion takes array element (k) and its index (i) which is the same for elements in myArray). In map and filter we use arrow functions.

Categories