Keep only selected keys in every object from array [duplicate] - javascript

This question already has answers here:
How to get a subset of a javascript object's properties
(36 answers)
Closed 12 months ago.
EDIT: not a duplicate, as my question does not ask for deleting a specific key, but all keys not found in an array.
In the below, function redux1 removes entries corresponding to keys not listed in keys_to_keep from data object.
Given that I have a list of object keys to keep, how can I rewrite redux1 in a cleaner way, prefarably utilizing map, filter or reduce?
var data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
var keys_to_keep = ['name', 'city']
function redux1(data) {
data.forEach((person) => {
Object.keys(person).forEach((key) => {
if (!keys_to_keep.includes(key)) {
delete (person[key])
}
})
})
console.log(data)
}
function redux2(data) {
var reduced = data.filter(person => Object.keys(person).filter(key => keys_to_keep.includes(key)))
console.log(reduced)
}
redux1(data)
//redux2(data)
My current redux2 will return objects will not remove age.

You could use a combination of Array#map and Array#reduce:
const data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
const keys_to_keep = ['name', 'city'];
const redux = array => array.map(o => keys_to_keep.reduce((acc, curr) => {
acc[curr] = o[curr];
return acc;
}, {}));
console.log(redux(data));

A version slightly shorter than the accepted answer using Array#map and Object.fromEntries():
const data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
const keys_to_keep = ['name', 'city'];
const redux1 = list => list.map(o => Object.fromEntries(
keys_to_keep.map(k => [k, o[k]])
));
console.log(redux1(data));

use Array.map and Array.forEach inside it :
var data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
var keys_to_keep = ['name', 'city']
const result = data.map(e => {
const obj = {};
keys_to_keep.forEach(k => obj[k] = e[k])
return obj;
});
console.log(result);

var data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
var keys_to_keep = ['name', 'city']
data=data.map(element => Object.assign({}, ...keys_to_keep.map(key => ({[key]: element[key]}))))
console.log(data)

data.reduce((r, c) => [ ...r, Object.entries(c).reduce((b, [k, v]) => keys_to_keep.includes(k) ? {...b, [k]: v } : b, {}) ],[])

You can use Object.entries
function objfilter(data,keys_to_keep){
return Object.fromEntries(Object.entries(data).filter(a=>keys_to_keep.includes(a[0])))
}
const data = [
{name: 'John', city: 'London', age: 42},
{name: 'Mike', city: 'Warsaw', age: 18},
{name: 'Jim', city: 'New York', age: 22},
{name: 'Celine', city: 'Tokyo', age: 54},
]
const keys_to_keep = ['name', 'city'];
console.log(objfilter(data,keys_to_keep))

Related

Push multiple objects to an already initialized, empty object array

People is my model, data is my new information, and the forEach is how I am trying to insert the new data into my model, but formatted to only the information I care about
people = [{name: '', age: 0}];
data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
data.forEach(person => {
people.push({
name: person.name,
age: person.age,
});
});
However, the result I get is this:
people = [
{name: '', age: 0},
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
I'm trying to have the object array look like this instead:
people = [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
However, I would like to know if theres a way to do it without an extra line of code (like popping the first element), and if theres a way to do it in one command? If not, I am open to suggestions. Thank you!
You're using the original array and not only that but also you're mutating the array.
You can use the function Array.prototype.map in order to generate a new array with the desired data.
const people = [{name: '', age: 0}];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => ({
name: person.name,
age: person.age,
}));
console.log(result);
You can also keep the desired keys and by using the functions Array.prototype.map and Array.prototype.reduce you can build the expected result:
const model = ["name", "age"];
const data = [
{id: '123', name: 'Bob', lastName: 'Guy', age: 40},
{id: '321', name: 'Michael', lastName: 'Park', age: 20},
]
const result = data.map(person => model.reduce((r, m) => ({...r, [m]: person[m]}), {}), []);
console.log(result);
Just in case you need to implement different person models, you can dinamically create the objects like this
peopleModel = [{ name: "", age: 0 }];
data = [
{ id: "123", name: "Bob", lastName: "Guy", age: 40 },
{ id: "321", name: "Michael", lastName: "Park", age: 20 },
];
const keysArr = Object.keys(peopleModel[0]);
const totalKeys = keysArr.length;
const people = data.reduce((acc, personObj) => {
const obj = {};
keysArr.forEach((key) => {
if (personObj[key]) {
obj[key] = personObj[key];
}
});
acc.push(obj);
return acc;
}, []);
console.log(people);
/* logs [
{name: 'Bob', age: 40},
{name: 'Michael', age: 20}
];
*/
but if you need a different model like
peopleModel = [{ name: "", age: 0, lastName: "" }]
you will get for the log the following:
[
{name: 'Bob', age: 40, lastName: 'Guy'},
{name: 'Michael', age: 20, lastName: 'Park'}
];
that way you do not need to hardcode the keys

Check if an a propery of an object from an array is contained in another array of object

Let's say I have these arrays of object
selectedNames = [
{label: 'Nicolas', value:'Nicolas'},
{label: 'Michael', value:'Michael'},
{label: 'Sean', value:'Sean'},
{label: 'George', value:'George'}
]
selectedWhatever = [
{label: 'Guitar', value: 'Guitar'},
{label: 'Bass', value: 'Bass'}
]
and then another array of objects like this:
list = [
{name: 'Nicolas', surname: 'Smith', birthplace: 'NewYork', whatever: 'Guitar'},
{name: 'Sean', surname: 'Narci', birthplace: 'LA', whatever: 'Bass'},
{name: 'George', surname: 'Rossi', birthplace: 'NewYork', whatever: 'Bass'},
{name: 'Fiona', surname: 'Gallagher', birthplace: 'Madrid', whatever: 'Drum'},
{name: 'Michael', surname: 'Red', birthplace: 'London', whatever: 'Triangle'},
]
and I want to filter list based on the datas I have in the others two arrays and group by birthplace, so I want this:
result = {
LA: [
{name: 'Sean', surname: 'Narci', birthplace: 'LA', whatever: 'Bass'},
],
NewYork: [
{name: 'Nicolas', surname: 'Smith', birthplace: 'NewYork', whatever: 'Guitar'},
{name: 'George', surname: 'Rossi', birthplace: 'NewYork', whatever: 'Bass'},
]
}
What I've done is the following and it works fine. Is there a smarter or more elegant way to do the same?
const obj = {};
list.map((res) => {
if ((data.selectedNames.map((r) => r.label).includes(res.name))
&& (data.selectedWhatever.map((r) => r.label).includes(res.whatever))
){
result[res.birthplace] = result[res.birthplace] ?? []:
result[res.birthplace].push(res);
}
})
Instead of creating and searching a new array of names and whatever for every checked entry, one could create those only once and store them together with the key to he checked as Sets:
const filters = {
name: new Set( selectedNames.map(it => it.label) )
};
const result = list.filter(it =>
Object.entries(filters).some(([key, set]) =>
set.has( it[key] )
)
);
The grouping part should really also be a reusable function.

Mapping data from two arrays which have different lengths and creating another array

I have two arrays which have two different lengths.
For example:
var array1 = [{name: 'Yuri', age: 2, gender: 'Male'}, {name: 'Akit', age: 19, gender: 'Male'}, {name: 'Kean', age: 14, gender: 'Female'}, {name: 'Jan', age: 29, gender: 'Male'}, {name: 'Max', age: 25, gender: 'Male'}, {name: 'Suzy', age: 20, gender: 'Female'}];
var array2 = [{name: 'Jan', gender: 'Male', occupation: 'Designer'}, {name: 'Max', gender: 'Male', occupation: 'Developer'}, {name: 'Suzy', gender: 'Female', occupation: 'Tester'}];
array1's length is 5 and array2's length is 3. I want to run a loop on both arrays and match the name. If the name matches then I want to extract the that particular object from 2nd array. As they have different lengths loop is breaking at the first array length and not reaching 2nd array's last element. I am running the for loop based on array2 length. Please help me with this.
Expected result:
Name of both arrays should be matched and create another array as below
var array3 = [{name: 'Jan',age: 29, gender: 'Male', occupation: 'Designer'},
same for other objects]
You could take a Set for one array's names and filter the second array.
var array1 = [{name: 'Yuri', age: 9, gender: 'Male'}, {name: 'Akit', age: 19, gender: 'Male'}, {name: 'Kean', age: 14, gender: 'Female'}, {name: 'Jan', gender: 'Male'}, {name: 'Max', gender: 'Female'}],
array2 = [{name: 'Jan', age: 9, gender: 'Male'}, {name: 'Max', age: 19, gender: 'Male'}, {name: 'Suzy', age: 14, gender: 'Female'}],
set2 = new Set(array2.map(({ name }) => name)),
result = array1.filter(o => set2.has(o.name));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
var arr1 = [{name: 'Jan', age: 19}, {name: 'Suzy', age: 29}, {name: 'Peter', age: 39}, {name: 'Bart', age: 49}, {name: 'John', age: 59}];
var arr2 = [{name:'Kean', job: 'Technician'},{name:'Nick', job:'Mathematics'},{name: 'Jan', job: 'Tester'}, {name: 'Suzy', job:'Developer'}, {name: 'Peter', job: 'Scrum master'}];
result = arr1.map(x=> {
y = arr2.find(z=> x.name == z.name);
x.job = y ? y.job : undefined;
return x;
});

What is smallest way to split object into array of object based on key/value pairs in Javascript?

I've got this object:
var obj = {
family : [{name: 'will', age: 30}, {name: 'husain', age: 12}],
friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}],
school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]
}
convert it into this
var obj = [
{family : [{name: 'will', age: 30}, {name: 'husain', age: 12}]},
{friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}]},
{school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]}
];
Write now I am using for..in to build a new array and create object with key as key for new object and so on.
I'm doing this right now
var arr = [];
for (let key in obj) {
arr.push({key: obj[key]})
}
I think Object.keys is your best option:
var obj = {
family : [{name: 'will', age: 30}, {name: 'husain', age: 12}],
friends : [{name: 'cody', age: 31}, {name: 'jeff', age: 11}],
school : [{name: 'daniel', age: 20}, {name: 'carl', age: 15}]
}
var r = Object.keys(obj).map(x => ({[x]: obj[x]}) )
console.log(r)

Javascript merge array values belonging to different keys in object

I have an object like this:
data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
I want to merge the array values of the keys, and make a single array of objects like this:
[ {name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}, {name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}, {name: 'MNO', age: '19'}, {name: 'PQR', age: '24'} ]
I went through the Lodash docs to find something, but cannot come up with the right combination. Does anyone know how to do this in a concise way, with Lodash (preferably), or something else? Thanks in advance!!
Extract the arrays using _.values(), and apply concat to the arrays:
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var result = Array.prototype.concat.apply([], _.values(data));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
You just need to convert the array like object to an array, then flatten it.
data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
console.log(
_.flatten(_.toArray(data))
)
<script src="https://cdn.jsdelivr.net/lodash/4.16.4/lodash.min.js"></script>
Without lodash, just plain old JS:
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var result = [];
for (var key in data) {
if (data.hasOwnProperty(key)) {
result = result.concat(data[key]);
}
}
console.log(result);
With the new Object.values() you may do as follows in pure JS ES6;
var data = { 0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
},
newData = [].concat(...Object.values(data));
console.log(newData);
Here is another pure javascript version.
var data = {
0: [{name: 'ABC', age: '43'}, {name: 'DEF', age: '20'}],
1: [{name: 'GHI', age: '41'}, {name: 'JKL', age: '25'}],
2: [{name: 'MNO', age: '19'}, {name: 'PQR', age: '24'}]
};
var newdata = Object.keys(data).reduce(function (a,b) {
return a.concat(data[b]);
}, []);
console.log(newdata);

Categories