How to iterate over multiple objects and remove a certain property - javascript

I'd like to preface this by saying I'm very new to coding (sorry if this is a very straightforward query - but it has me stumped!)
I'm trying to iterate through objects for the first time and delete a specified key-value pair.
I have a function with an array of User objects and within that array I want to delete the person's name from each object.
I've tried iterating through the object using the .length property but get the result Reference Error: name is not defined.
When I try the following it works (but this isn't ideal as I want the code to run without having the specify the individual index number):
delete users[0].name;
delete users[1].name;
for (let i = 0; i < users.length; i++) {
if (users[i] === name) {
users.splice(i, 1);
}
return users;
}
Actual result: ReferenceError: name is not defined
I want the result to remove the name: ' ' value from the object.

You could iterate the array and delete the unwanted propery. This mutates the given data.
for (var i = 0; i < users.length; i++) {
delete users[i].name;
}
An advanced version takes a destructuring with the unwanted property and a rest syntax for getting all other properties and return this object.
users = users.map(({ name, ...object }) => object);

A simple approach would be to loop over the items using forEach and delete the desired property.
let users = [{name: "a", prop1: 1, prop2: 2},{name: "b", prop1: 2, prop2: 2}, {name: "c", prop1: 3, prop2: 2}];
users.forEach(user => {
delete user['name'];
});
console.log("after deleting property", users);

To delete the key-value pair...
var users = [
{name: "John", role: "Cleaner"},
{name: "Jim", role: "Sergent"},
{name: "Jackhn", role: "Baker"},
{name: "Josh", role: "tinker"},
{name: "Jenny", role: "Soldier"}
];
for (var i=0; i < users.length; i++) {
delete users[i].name;
}

There’s only one code block visible in the question, but do you mean delete users[0].name; delete users[1].name; does what you want when there are two users and you’d like to convert that to a loop?
If yes,
for (let user of users) {
delete user.name;
}
That loops over every user in the array and deletes the name property of each one.

Related

JS - How to add key:value pairs from objects nested in arrays to other objects nested in another array

I know it has been countlessly asked and I assure you that I've read a lot of posts, articles, etc., and watched a lot of videos but nothing seems to click.
so there we go :
Here are 2 arrays with partial information about every person
let arr1 = [{id:00, name:Ben, city:Philadelphia}, {id:01, name:Alice, city:Frankfurt}, {id:02, name:Detlef, city:Vienna}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
And there is the desired final result: an array including the name, city, and age of each person
let arr3 = [{name:Ben, city:Philadelphia, age:39}, {name:Alice, city:Frankfurt, age:75 }, {name:Detlef, city:Vienna, age:18}]
What's the situation? Two arrays both containing objects. each nested object has an id. That id is the common key in each array of objects.
What do you want to do? : I want to create a third array including information from both arrays (from arr1: name and city; from arr2:age).
What have you tried so far? : I couldn't manage to achieve anything worth showing. this minimal example is intended to show you a simple example of my current situation which is: I've got an array that is in the LocalStorage on one hand and an API on the other, both contain some info regarding particular objects (let's say, persons). I want to create an array that will contain all the information regarding each person for easier manipulation afterward (DOM generation, etc.).
I've managed to store both arrays in two "local" arrays but the problem is still there: I can't figure out how to make an array where items are getting their key/value from two separate sources.
Thank you for your help!
You can use reduce method on the arr with array as an inital value, and inside try to find the corrospending item with same id and destruct the object from the id and merge the two object with spread operator.
let arr1 = [{id:00, name:'Ben', city: 'Philadelphia' }, {id:01, name:'Alice', city:'Frankfurt'}, {id:02, name:'Detlef', city:'Vienna'}]
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}]
const result = arr1.reduce((acc, { id: id1, ...rest1 }) => {
const { id: id2, ...rest2 } = arr2.find(i => i.id === id1)
acc.push({ ...rest1, ...rest2 })
return acc;
}, [])
console.log(result)
You can solve it in various ways, here first I have implemented a dict with key as id to get the value in O(1) while iterating arr2.
So the overall time complexity is O(n+k) where n is len of arr1 and k is len of arr2.
let arr1 = [{id:00, name: "Ben", city: "Philadelphia"}, {id:01, name:"Alice", city:"Frankfurt"}, {id:02, name:"Detlef", city:"Vienna"}];
let arr2 = [{id:02, age:18}, {id:00, age:39}, {id:01, age:75}];
const refMapById = arr1.reduce((refMap, {id, name, city}) => {
refMap[id] = {name, city};
return refMap;
}, {});
const result = arr2.reduce((resultArray, {id, age}) => [...resultArray, { ...refMapById[id],age}], []);
console.log(result);
Cheers!
It will be worth creating a dictionary from one of the arrays anyway since using .find() inside of .reduce() adds an unnecessary nested loop. But instead of reducing the second array as was suggested you can simply .map() it into the result array, like so:
let arr1 = [{ id: 00, name: "Ben", city: "Philadelphia" }, { id: 01, name: "Alice", city: "Frankfurt" }, { id: 02, name: "Detlef", city: "Vienna" }];
let arr2 = [{ id: 02, age: 18 }, { id: 00, age: 39 }, { id: 01, age: 75 }];
const groupedById = arr1.reduce((group, person) => {
group[person.id] = person;
return group;
}, {});
const result = arr2.map((personPartFromSecondArray) => {
const personPartFromFirstArray = groupedById[personPartFromSecondArray.id];
if (typeof personPartFromFirstArray !== "undefined") {
return { ...personPartFromFirstArray, ...personPartFromSecondArray }
}
return personPartFromSecondArray;
});
console.log(result);

Javascript: map function appending to an object

I have a map function which is iterating a response i received from backend. I'm iterating the response as 'tab' like the code below, what i want to do is to insert 'tab.name' as an key inside the object MyObject
my code:
var MyObject = {}
response.data.rows.map(tab => {
MyObject = {
...MyObject,
tab.name
}
})
What i expect is that my object MyObject has every keys and values with the name of tab, e.g:
{
name1: name1,
name2: name2,
name3: name3
}
The problem is that i can not use tab.name inside object
You could use collectjs, goes good..
Anyway if you want to have the keys just do a foreach
let response = [
{name: 'name1', age: '22'},
{name: 'name2', age: '25'},
{name: 'name3', age: '2'},
]
var MyObject = {}
response.forEach(tab => {
MyObject[tab.name] = tab.name
})
console.log(MyObject)
If you really want to use .map(), you could use to create an array of arrays, where each sub-array has a length of 2, and holds the given value at each index.
Then you can use Object.fromEntries() to add the properties from that array structure.
var response = {data:{rows:[{name:"foo"}, {name:"bar"}, {name:"baz"}]}};
var key_val_props = response.data.rows.map(({name}) => [name, name]);
var MyObject = Object.fromEntries(key_val_props);
console.log(MyObject);
Theres no need to copy the object just do
MyObject[tab.name] = tab.name;
I'd also avoid using .map since it will be returning the new reference which I dont think that is what you want.

Working with list of arrays and accesing its elements in React

I'm using two objects in my app.
First type looks like this:
and I can access the gender like this: data.results[0].gender
So to elaborate on this i decided to record all people in the data array and now i have an object that looks like this:
how do I reference and access names of selected people from an object like this?
Thanks
To be fair, this seems like a poor/messy way to keep data in general, but maybe you could define a map between your people's ids or uuids or usernames, let's say, and the corresponding objects and then call them by their ids to retrieve the info you need on them:
const peopleMap = new Map();
for (person in array){
peopleMap.set(person.id.value, person)
}
ex.
let aparticularid = '92bd-asd1-24nas-213c-3cac-31ac';
let person = peopleMap.get(aparticularid);
let fullname = person.title + ' ' + person.first + ' '+ person.last;
Realistically you'd retrieve the particular id from elsewhere or some event. Or you can map names to the corresponding objects if you can guarantee their uniqueness(if they are not unique, the objects will be overridden in the map)
You can use .map() to iterate over the items of an Array.
Example -
yourArray.map(x => {
const {title, first, last} = x.name;
console.log(`${title} | ${first} } ${last}`)
})
const yourArray = [
{
id: {name: 'HETU', value: 'NAANANFSF'},
name: {title: 'Ms.', first: 'Mila', last: 'Heitet'}
},
{
id: {name: 'Tom', value: 'TANN'},
name: {title: 'Mr.', first: 'Tom', last: 'Altar'}
},
{
id: {name: 'HARRY', value: 'HARSFF'},
name: {title: 'Mr.', first: 'Harry', last: 'Krishna'}
}
];
yourArray.map(x => {
const {title, first, last} = x.name;
console.log(`${title} | ${first} | ${last}`)
})
Based on the second screenshot, this is an array of objects. Lets call the array arr then you can access the name of the i-th person in the following way:
arr[i].name.first and arr[i].name.last respectively.

Am I updating the React state correctly?

In my React state, I have the state:
this.state = {
users: [{
id: 1,
name: "john",
age: 27
}, {
id: 2,
name: "ed",
age: 18
}, {
id: 3,
name: "mel",
age: 20
}]
}
I am rendering the name correctly. When you click on the name, it should remove the name, which will need an onClick that takes in a function and that returns a removeUser function.
It is my understanding that you do not want to mutate the state in React, but return a new state. So, in my removeUser function, I did:
removeUser(index) {
// Making a new copy of the array
const users = [...this.state.people].splice(index, 1);
this.setState({ users });
}
I bind my method with this.removeUser = this.removeUser.bind(this).
When I tested out my code, I am removing the users as expected. However, when I run my code against a test that my friend wrote, I got a failed test that said: Expected 1 to be 0
That message tells me that I must be mutating the state somehow, but I am not sure how. Am I returning a new array and updating the state correctly? Can someone explain to me how I should update my state correctly in this case?
Here is the full code:
class Group extends Component {
constructor(props) {
super(props);
this.state = {
users: [
{id: 1, name: "john", age: 27},
{id: 2, name: "ed", age: 18},
{id: 3, name: "mel", age: 20}
]
}
this.removeUser = this.removeUser.bind(this);
}
removeUser(index) {
const users = [...this.state.users].splice(index, 1);
this.setState({ users });
}
render() {
const list = this.state.users.map((user, i) => {
return (
<div onClick={() => this.removeUser(i)} key={i}>{user.name}</div>
);
});
return (
<div>
{list}
</div>
);
}
}
you could also change your onClick and pass it the user.id instead of the index. that would allow you to filter the results instead of needing to splice the array.
onClick={() => this.removeUser(user.id)}
removeUser(id) {
const users = this.state.users.filter((user) => user.id !== id);
this.setState({ users });
}
const users = [...this.state.users].splice(index, 1)
looks like it should be removing an item from a collection, which I suppose it technically is. The problem is that users doesn't contain the list of users you want to keep.
Instead, splice has modified your new array in-place and then returned the removed items:
splice docs
Return value
An array containing the deleted elements. If only one element is removed, an array of one element is returned. If no elements are removed, an empty array is returned.
Instead, if you'd like to use splice, create a new array:
const users = [...this.state.users]
and then splice the new array:
users.splice(index, 1)
You'll run into a similar issue if you need to sort an array.
The issue of modifying data in-place is generally frowned upon for react, in favor of immutable references. This is because React uses a lot of direct comparison of objects as a heuristic approach to speed things up. If your function modifies an existing object instance, React will assume the objects haven't changed.
The act of copying to a new object and then operating on the data comes with some tradeoffs. For removing a single item, it's negligible. For removing many items, you may be better served by an alternative method, such as multiple slice calls:
const users = [
...this.state.users.slice(0, index)
...this.state.users.slice(index + 1)
]
However this too is quite verbose.
Another approach is to use an immutable variant of splice:
// this quick example doesn't handle negative start indices
const splice = (start, deleteCount, ...items) => arr => {
const output = []
let i
for (i = 0; i < start && i < arr.length; i++) {
output.push(arr[i])
}
output.push(...items)
for (i += deleteCount; i < arr.length; i++) {
output.push(arr[i])
}
return output
}
const users = splice(index, 1)(this.state.users)
You should use slice() instead of splice() because splice() mutates the original array, but slice() returns a new array. Slice() is a pure function. Pure is better!!
removeUser(index) {
const users = [
...this.state.users.slice(0, index),
...this.state.users.slice(index+1)
];
this.setState({ users });
}
Here is JS Fiddle

Use object as a dictionary or list in AngularJS?

I currently store my data in AngularJS as lists. Such as:
var users = [{id: 1, name: "Mary"}, {id: 2, name: "John"}];
This however leads to for-loops whenever I want to change something.
function gotChangesFromServer(data) {
for (var i=0; i < users.length; ++i) {
if (users[i].id == data.id) {
users[i] = data;
break;
}
}
}
I was looking into underscore.js and found it has some nice functions like values() to get a list of values from a dictionary-like structure. So I could instead do:
var users = { "1": {id: 1, name: "Mary"}, "2": {id: 2, name: "John"} };
function gotChangesFromServer(data) {
users[data.id] = data;
}
function getUsers() {
return _.values(users);
}
But, I realized that AngularJS will call my getUsers() function a lot. On every filter operation or any change to the data.
So it seems I have to choose between two bad solutions. Either for-looping all the time when changing the users, or accessing a user based on id. Or, calling values() often, which I suppose, basically is a for-loop over the properties in the users object.
I expect to have around 1000 - 5000 users in the users list / dictionary.
How would you do it?
You may use underscores findWheremethod to retrieve certain objects:
_.findWhere(users, {id: 123}).data = newDataForThisUser;
Your gotChangesFromServer would then look like this:
function gotChangesFromServer(data) {
_.extend(_.findWhere(users, {id: data.id}), data);
}

Categories

Resources