-1

I have the following array if objects:

[{id: 0
name: "Weight"
options: [
"250gr","500gr"],
position: 0
variation: true
visible: true},
{id: 0
name: "Roast"
options: ["Light", "Medium, "Dark],
position: 0
variation: true
visible: true},
{id: 0
name: "Packaging"
options: [
"Tin","Card"],
position: 0
variation: true
visible: true}
]

Then i elaborate the following one:

[{id: 0, name: "Weight", option: "250gr"},
{id: 0, name: "Roast", option: "Medium"},
{id: 0, name: "Packaging", option: "Card"},
{id: 0, name: "Weight", option: "250gr"},
{id: 0, name: "Roast", option: "Light"},
{id: 0, name: "Packaging", option: "Card"}
]

is it possible to change the value of 'options' array of the first one, according to the second set of options? i need to obtain something like:

[{id: 0
    name: "Weight"
    options: [
    "250gr"],
    position: 0
    variation: true
    visible: true},
    {id: 0
    name: "Roast"
    options: ["Light", "Medium"],
    position: 0
    variation: true
    visible: true},
    {id: 0
    name: "Packaging"
    options: [
    "Card"],
    position: 0
    variation: true
    visible: true}
    ]
popeating
  • 386
  • 1
  • 2
  • 16

2 Answers2

1

tl;dr Transform second options array into an Object or Map for lookup

How I see it, efficiency comes in two main flavors:

  1. Efficiency of the developer (maintenance)
  2. Efficiency of your code (performance/speed)

Typically, you want to start with #1, but sometimes your knowledge of #2 dictates your overall approach (as you'll see in my example).

For maintenance: What is simplest for a future dev (possibly you) to read and understand? Also, what is easiest to scale/change and reuse? There's so much to this topic and it really separates the junior devs from the seniors. A more declarative approach often fits well here. This is why I would recommend Array functions like Array.map() and/or Array.reduce() instead of for loops. Also, these assist with my other recommendation: Immutability or, at least, treating data as though it is immutable. But, this often involves cloning data, which may decrease performance somewhat. (NOTE: Spread syntax seems to be fastest at cloning arrays)

For performance: One of the fastest ways I know to do a search like this is with a key lookup against a hashmap (in JS, an Object or a Map does the trick). So, I would start there. It would be ideal if your second options array was already an Object, rather than an Array, but we can at least transform what you have. You can further simplify the logic by changing the data later (and removing the transform code), if that's an option for you.

The following approaches should satisfy both types of efficiency to some extent. Here's my best example of all that put together, using an Object:

const options = [
  { id: 0, name: "Weight", position: 0, variation: true, visible: true, options: ["250gr","500gr"] },
  { id: 0, name: "Roast", position: 0, variation: true, visible: true, options: ["Light", "Medium", "Dark"] },
  { id: 0, name: "Packaging", position: 0, variation: true, visible: true, options: ["Tin","Card"] },
];

const options2 =  [
  { id: 0, name: "Weight", option: "250gr" },
  { id: 0, name: "Roast", option: "Medium" },
  { id: 0, name: "Packaging", option: "Card" },
  { id: 0, name: "Weight", option: "250gr" }, // Duplicate
  { id: 0, name: "Roast", option: "Light" },
  { id: 0, name: "Packaging", option: "Card" }, // Duplicate
];

// Transform options2 (Create an Object for hash lookup)
const options2Dictionary = options2.reduce((obj, o) => {
  const arr = obj[o.name] ?? [];
  if (!arr.includes(o.option)) arr.push(o.option); // ignore duplicates
  obj[o.name] = arr;
  return obj;
}, {});

// "Replace" (I'm copying values into new objects, instead of modifying)
const updatedOptions = options.map(o => ({
  ...o,
  options: [...(options2Dictionary[o.name] ?? [])], // override "options" (clone array)
}));

console.log(updatedOptions);

Same thing, using Map:

const options = [
  { id: 0, name: "Weight", position: 0, variation: true, visible: true, options: ["250gr","500gr"] },
  { id: 0, name: "Roast", position: 0, variation: true, visible: true, options: ["Light", "Medium", "Dark"] },
  { id: 0, name: "Packaging", position: 0, variation: true, visible: true, options: ["Tin","Card"] },
];

const options2 =  [
  { id: 0, name: "Weight", option: "250gr" },
  { id: 0, name: "Roast", option: "Medium" },
  { id: 0, name: "Packaging", option: "Card" },
  { id: 0, name: "Weight", option: "250gr" }, // Duplicate
  { id: 0, name: "Roast", option: "Light" },
  { id: 0, name: "Packaging", option: "Card" }, // Duplicate
];

// Transform options2 (Create a Map for hash lookup)
const options2Dictionary = options2.reduce((map, o) => {
  const arr = map.has(o.name) ? map.get(o.name): [];
  if (!arr.includes(o.option)) arr.push(o.option); // ignore duplicates
  map.set(o.name, arr);
  return map;
}, new Map());

// "Replace" (I'm copying values into new objects, instead of modifying)
const updatedOptions = options.map(o => ({
  ...o,
  options: [...(options2Dictionary.get(o.name) ?? [])], // override "options" (clone array)
}));

console.log(updatedOptions);

Finally, if your data was already an Object:

const options = [
  { id: 0, name: "Weight", position: 0, variation: true, visible: true, options: ["250gr","500gr"] },
  { id: 0, name: "Roast", position: 0, variation: true, visible: true, options: ["Light", "Medium", "Dark"] },
  { id: 0, name: "Packaging", position: 0, variation: true, visible: true, options: ["Tin","Card"] },
];

const options2 = {
  "Weight": [ "250gr" ],
  "Roast": [ "Medium", "Light" ],
  "Packaging": [ "Card" ],
};

// "Replace" (I'm copying values into new objects, instead of modifying)
const updatedOptions = options.map(o => ({
  ...o,
  options: [...(options2[o.name] ?? [])], // override "options" (clone array)
}));

console.log(updatedOptions);
BCDeWitt
  • 4,540
  • 2
  • 21
  • 34
  • that was really exhaustive, loved the last example, but unluckly my options2 isnt an object so the first 2 are wonderful! (anyway, i can convert it, but it would take some elaboration so i can keep the elaboration on the "replace" part) – popeating Dec 10 '20 at 21:02
-1

i solved this way (locattributes is the first object, newopt the second) i don't know if there is a more efficient way to do i

for (const property in locattributes) {
      let locop = [];
      locattributes[property].options = [];
      newopt.forEach((no) => {
        if (no.name === locattributes[property].name) {
          if (locop.indexOf(no.option) === -1) {
            locop.push(no.option);
          }
        }
      });
      locattributes[property].options = locop;
    }
popeating
  • 386
  • 1
  • 2
  • 16