1

I've got two arrays:

arrayOne = ["green","blue","purple"]

and

arrayTwo = [
  { name: "green", id: 1 },
  { name: "red", id: 2 },
  { name: "yellow", id: 3 },
  { name: "blue", id: 8 },
]

I want the return array to be [1, 8, 9], with "purple" being pushed as an object at the end of arrayTwo (with a new id).

What's the most efficient way to go about this?

5
  • Is 9 the id of purple? Commented Nov 25, 2019 at 2:32
  • Covert array into hash map where key will be name and value will be I'd, then doing your operation will take O(n) Commented Nov 25, 2019 at 2:34
  • Are the ids sorted on arrayTwo? Commented Nov 25, 2019 at 2:39
  • @Eddie Let's assume they are. Commented Nov 25, 2019 at 2:40
  • @StevenB. Purple doesn't have an id (yet), it's not present in arrayTwo Commented Nov 25, 2019 at 2:43

3 Answers 3

2

The following code uses map to either retrieve the id of the element in the second array or, if that element doesn't exist, create a new one by incrementing the last id in that array by 1.

arrayOne = ["green","blue","purple"]

arrayTwo = [
  { name: "green", id: 1 },
  { name: "red", id: 2 },
  { name: "yellow", id: 3 },
  { name: "blue", id: 8 },
]

const newArr = arrayOne.map(color => {
  const found = arrayTwo.find(el => el.name === color);
  if (found) {
    return found.id;
  }
  const newId = arrayTwo[arrayTwo.length - 1].id + 1;
  arrayTwo.push({ name: color, id: newId });
  return newId;
});

console.log(newArr);

console.log(arrayTwo);

Edit: Note that it may be brittle to assume the last item in arrayTwo contains the highest id. In that case, you can always find the max ID:

const newArr = arrayOne.map(color => {
  let maxId = 0;
  const found = arrayTwo.find(el => {
    if (el.id > maxId) {
      maxId = el.id;
    }
    return el.name === color 
  });
  if (found) {
    return found.id;
  }
  const newId = maxId + 1;
  arrayTwo.push({ name: color, id: newId });
  return newId;
});

A thought on efficiency

If you have any concerns about efficiency if this is going to be a large (hundreds/thousands/more) element arrays, you can consider changing arrayTwo to an object with color as a key:

const arrayOne = ["green","blue","purple"];

const arrayTwo = [
  { name: "green", id: 1 },
  { name: "red", id: 2 },
  { name: "yellow", id: 3 },
  { name: "blue", id: 8 },
];

let maxId = 0;

// Create map
const arrayTwoMap = arrayTwo.reduce((acc, el) => {
  if (el.id > maxId) maxId = el.id;
  acc[el.name] = el.id;
  return acc;
}, {});

// Find elements
const newArr = arrayOne.map(el => {
  const found = arrayTwoMap[el];
  if (found !== undefined) {
    return found;
  }
  const newId = maxId + 1;
  arrayTwoMap[el] = newId;
  return newId;
});

console.log(newArr);

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

2 Comments

Note that it may be brittle to assume the last item in arrayTwo contains the highest id. In that case, you can always find the max ID.
props for being able to figure out what the OP was expecting but also for such a detailed reply Nick
1

this code can achieve what you want:

let arrayTwo = [
  { name: "green", id: 1 },
  { name: "red", id: 2 },
  { name: "yellow", id: 3 },
  { name: "blue", id: 8 },
];

let indexes = {}, lastId = 0;

arrayTwo.forEach(({name, id}) => { 
  if(indexes[name] = id, id > lastId) lastId = id
});

function getResult(a){
  return a.map(e => indexes[e] || (arrayTwo.push({name: e, id: ++lastId}), indexes[e] = lastId))
}

// arrayOne contents
let result = getResult(["green", "blue", "purple"]);
console.log(arrayTwo, result);

// with other data
let result2 = getResult(["cyan", "blue", "purple", "azure"]);
console.log(arrayTwo, result2);

Hope it helps

Comments

1

You can convert arrayTwo into a Map (for efficiency), where the name is the key and the id is the value. Then, once you have done that, you can .map() arrayOne into an array of id by using each name element as a look-up key to get its associated id. If you find a name which is not in the Map, then you can add a new object, to your arrayTwo array, and increment the id counter:

const arrayOne = ["green","blue","purple"];
const arrayTwo = [{ name: "green", id: 1 }, { name: "red", id: 2 }, { name: "yellow", id: 3 }, { name: "blue", id: 8 },];

let [{id:l_id}] = arrayTwo.slice(-1);
const lut = new Map(arrayTwo.map(({name, id}) => [name, id]));
const res = arrayOne.map(name => lut.get(name) || (arrayTwo.push({name, id: ++l_id}), l_id));
console.log(res);
console.log(arrayTwo);

If you're only concerned about the return value (and not changing array 2), you can simplify the code down:

const arrayOne = ["green","blue","purple"];
const arrayTwo = [{ name: "green", id: 1 }, { name: "red", id: 2 }, { name: "yellow", id: 3 }, { name: "blue", id: 8 },];

let [{id:l_id}] = arrayTwo.slice(-1);
const lut = new Map(arrayTwo.map(({name, id}) => [name, id]));
const res = arrayOne.map(
              name => lut.get(name) || ++l_id
            );
console.log(res);

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.