9

I have an array of users, and I'd like to update one of those users.

users = [
  {userId: 23, userName:"foo"},
  {userId: 34, userName:"wrong"},
  {userId: 45, userName:"baz"}
  {userId: 56, userName:"..."},
]

updatedUser = {
  userId: 34,
  userName: bar
}

I'm using underscorejs. I thought the simplest way is to find the index of the user to be updated, and then just set the value of that user to my updated value. Unfortunately, underscore's indexOf function doesn't accept properties, only values. To use it, I'd have to first user findWhere and then pass what that returns into indexOf:

var valueOfUpdatedUser = _.findWhere(users, { userId: updatedUser.userId })
var indexOfUpdatedUser = _.indexOf(users, valueOfUpdatedUser)
users[indexOfUpdatedUser] = updatedUser;

A second approach would be to use reject to remove the matched user, and then push my updated user to the array.

Surely there's a better, simpler way?

4
  • You could iterate over the array yourself Commented May 13, 2014 at 21:40
  • You could loop over the array until you find the user. Or, use an object instead with the userId as the key. Commented May 13, 2014 at 21:40
  • Since an Id is by definition unique, you can create users as an object and use userId as keys. users = { 23: { userName: 'foo' }, 34: { userName: 'wrong' }};. That makes updating very easy: users[34].userName = 'bar';. Commented May 13, 2014 at 21:43
  • Since userId is unique I really suggest you to use hash instead of array 23: { userinfo here }, 34: { another userinfo here }. In this case replace code will be just users[%id%] = { new info here }; Commented May 13, 2014 at 21:44

3 Answers 3

28

You can use extend after findWhere. It's not technically the same as replacing the object with another instance entirely, but it eliminates the extra loop over the array:

_.extend(_.findWhere(users, { userId: updatedUser.userId }), updatedUser);

If this is still not satisfactory then your best bet is probably to iterate manually.

I am deliberately leaving the "object properties keyed by user id" approach out of the discussion because in practice it's not uncommon to have an array in hand to begin with (e.g. the user array was retrieved by an API).

Sign up to request clarification or add additional context in comments.

1 Comment

In my case, I used "findIndex" instead of "findWhere". Maybe it's a matter of versions for the Underscore in use, but it seems to work the same way, so thank you for this info and code!! Happy coding!
2

Unfortunately, underscore's indexOf function doesn't accept properties, only values.

In this case, what you can use instead of indexOf is to use findIndex

From the docs:

Similar to _.indexOf, returns the first index where the predicate truth test passes; otherwise returns -1.

_.findIndex([4, 6, 8, 12], isPrime);
=> -1 // not found
_.findIndex([4, 6, 7, 12], isPrime);
=> 2

So in this case you'd do something like this:

var indexOfUpdatedUser = _.findIndex(users, { userId: updatedUser.userId });
users[indexOfUpdatedUser] = updatedUser;

Update: A check for a -1 value would probably be a good idea (i.e. if the index isn't found)

Comments

1

Instead of an array, it would be easier an object with ids as property names:

var users = {
  23: {userName: "foo"},
  34: {userName: "wrong"},
  45: {userName: "baz"},
  56: {userName: "..."}
};

Then, to update the data of some user, just use

users[updatedUserId] = updatedUserData;

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.