1

I have two array of objects (users and deposits).

const users = [
    {
        _id: 1,
        username: 'tajmirul',
        email: '[email protected]',
    },
    {
        _id: 2,
        username: 'tajmirul2',
        email: '[email protected]',
    },
];

const deposits = [
    {
        _id: 1,
        userId: 1,
        amount: 250,
    },
    {
        _id: 2,
        userId: 1,
        amount: 500,
    },
];

I want to calculate total deposit for each user and update the users array. like this

// modified users array will look like this
[
    {
        _id: 1,
        username: 'tajmirul'
        deposit: 750,
    },
    {
        _id: 2,
        username: 'tajmirul2'
        deposit: 0,
    }
]

I tried this

users.forEach((user, index) => {
    deposits.forEach(deposit => {
        if (user._id === deposit.userId) {
            if (users[index].deposit) {
                users[index].deposit += deposit.amount;
            } else {
                users[index].deposit = deposit.amount;
            }
        }
    });
});

In this case, the time complexity is O(m * n). Is there any way to reduce the time complexity?

1
  • Are the arrays aligned? (i.e. are users[i] and deposits[i] always the for the same id?) If so, you only need a single const mapped = users.map((user, i) => /* combine user and deposits[i] */). Commented Aug 26, 2022 at 22:28

3 Answers 3

1

You can create a hash map and index deposits by user Ids.

This gives you O(m)

Size of Users = n, Size of Deposits = m

After that, you can iterate over users and that would be O(n)

In the end, the time complexity will be O(MAX(m,n))

const users = [
  {
    _id: 1,
    username: 'tajmirul',
    email: '[email protected]',
  },
  {
    _id: 2,
    username: 'tajmirul2',
    email: '[email protected]',
  },
];

const deposits = [
  {
    _id: 1,
    userId: 1,
    amount: 250,
  },
  {
    _id: 2,
    userId: 1,
    amount: 500,
  },
];


const depositsMap = new Map();

for (const deposit of deposits) { // O(m)
  if (depositsMap.has(deposit.userId)) {
    const prevDeposit = depositsMap.get(deposit.userId);
    depositsMap.set(deposit.userId, prevDeposit + deposit.amount);
  } else {
    depositsMap.set(deposit.userId, deposit.amount ?? 0);
  }
}

const aggregatedUsers = users.map(user => { // O(n)
  return {
    _id: user._id,
    username: user.username,
    deposit: depositsMap.get(user._id) ?? 0,
  };
});

console.log(aggregatedUsers);

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

Comments

0
const usersWithAmount = users.map((user) => {
  const { _id } = user;
  const depositsFiltered = deposits.filter(({ userId }) => userId === _id);
  if (depositsFiltered.length > 0) {
    return {
      ...user,
      deposit:
        (user?.deposit ?? 0) +
        depositsFiltered.reduce((acc, { amount }) => (acc + amount), 0),
    };
  }
  return { ...user, amount: 0 };
});

3 Comments

I think time complexity is the same. O(m * n). Can you reduce the time complexity?
I'd say the only difference here is that map is faster than forEach
or do it from different side - deposits.map(... @TajmirulIslam
0

You might first reduce the deposits to {userId:total} which is say O(n),
then update the users which is O(m):

const users = [
    {
        _id: 1,
        username: 'tajmirul',
        email: '[email protected]',
    },
    {
        _id: 2,
        username: 'tajmirul2',
        email: '[email protected]',
    },
];

const deposits = [
    {
        _id: 1,
        userId: 1,
        amount: 250,
    },
    {
        _id: 2,
        userId: 1,
        amount: 500,
    },
];

const userDeposits = deposits.reduce((a, {userId, amount}) => (a[userId] = (a[userId] || 0) + amount, a), {}) // O(n)

users.forEach(u => u.amount = userDeposits[u._id] || 0) // O(m)

console.log(users)
.as-console-wrapper {
  top: 0;
  max-height: none !important;
  }

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.