4

So I have this main array:

 const purchaseData = [
  {
    product_id: "product_id_1",
    localized_title: "Product Title 1",
    ... other attributes
  },
  {
    product_id: "product_id_2",
    localized_title: "Product Title 2",
    ... other attributes
  },

And I'd like to replace the localized_title with an array that contains some updated localized_title for certain product_ids

example:

updatedData = [
  {
    product_id: "product_id_1",
    localized_title: "Updated Product Title 1",
    ...other random attributes // different from the attributes in the objects of purchaseData
  },
];

In this case, the purchaseData's first child only should have its localized_title updated. Is there an elegant way of doing this without using For...lopps and without mutating the data? I've tried many ways but I seem to write too many lines of code (not very clean).

This is what I tried:

const updatedData = purchaseData.map(obj => {
    const foundObject = originalProducts.find(
      o => o.product_id === obj.product_id,
    );
    const localized_title = foundObject && foundObject.localized_title
    if (localized_title) {
        return {...obj, localized_title}
    }
    return obj;
  });
7
  • 1
    Maybe you can try with map() or reduce(). Commented Jan 21, 2020 at 21:02
  • 3
    What exactly have you tried? What is "unclean" about it, and what actual problem is that causing? Commented Jan 21, 2020 at 21:02
  • 3
    Elegance is in the eye of the beholder and I can tell you, as someone who reviews code all day long, I'd much rather see "too many" lines of code than too few "clever" lines of code. Commented Jan 21, 2020 at 21:04
  • 1
    I updated the question to include what I tried. I don't need to merge, but instead to replace some values, because the 2 arrays contain objects which have different attributes Commented Jan 21, 2020 at 21:09
  • 1
    I'm mostly concerned about other developers reading this code, I feel like it's too complicated :/ Commented Jan 21, 2020 at 21:21

2 Answers 2

3

I'd use a Map to simplify retrieving the objects(this also makes the code O(n)):

  const productById = new Map(products.map(it => ([it.product_id, it])));

  const updated = purchases.map(purchase => {
    const product = productById.get(purchase.product_id);

    if (product && product.localized_title) {
      return { ...purchase, localized_title: product.localized_title, };
    }

    return purchase;
 });
Sign up to request clarification or add additional context in comments.

5 Comments

Also your logic isn't exactly equivalent. Your if would need to be if (product && product.localized_title). That's why I stored the intermediate expression to a const and used the shorthand property notation instead.
@patrick indeed, wasn't quite sure if that behaviour is wanted. I'd still prefer if(product && ...) then as it clearly states the intent.
I agree with the logic mentioned by @PatrickRoberts if (product && product.localized_title)
@skoltz if that was intended then ... Also I rejected your edit cause I think removing the data increases readability ...
@Skoltz do keep in mind that if localized_title is an empty string on the new object, the old object will be returned since "" is false-y.
2

It will be worth it to optimize your lookup using a Map to reduce the search for foundObject from O(n) to O(1), and instead of having two return statements, you could combine them into one:

const originalProductsMap = new Map(
  originalProducts.map(o => [o.product_id, o])
);

const updatedData = purchaseData.map(oldData => {
  const newData = originalProductsMap.get(oldData.product_id);
  const localized_title = newData && newData.localized_title;

  return localized_title
    ? { ...oldData, localized_title }
    : oldData;
});

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.