0

I have two array of objects like this:

const officers: any[] = [
  { id: 20, name: 'Captain Piett' },
  { id: 24, name: 'General Veers' },
  { id: 56, name: 'Admiral Ozzel' },
  { id: 88, name: 'Commander Jerjerrod' }
];

const searchAndChangeFor: any[] = [
  { id: 56, name: 'New Name', additionalData: 1 },
];

I want to find elements from searchAndChangeFor in officers and modify content. Usually If I have one element I do this:

officers.map((item) => {
    // I want to modify id: 56 and update officers here.
    item.id === 56 ? { ...item, name: 'Change name for 56' } : item
}); 

But I need to search by array not single element so I've tried this but not succeeded:

officers.map((item) => {
   searchAndChangeFor.find((item2) => {
       item.id === item2.id? { ...item, name: 'Change name for 56' } : item
   }); 
}); 

Expected Output:

  { id: 20, name: 'Captain Piett' },
  { id: 24, name: 'General Veers' },
  { id: 56, name: 'New Name', additionalData: 1 },
  { id: 88, name: 'Commander Jerjerrod' }

It goes crazy with array. How can I find elements in officers based on searchAndChangeFor and change its name? I also want to keep all other existing items in officers.

3
  • Either add a return inside map and find or remove the {} for implicit return Commented May 28, 2019 at 8:09
  • Do all items in searchAndChangeFor exist in officers? Commented May 28, 2019 at 8:10
  • Yes. No new values in searchAndChangeFor Commented May 28, 2019 at 8:11

6 Answers 6

3

You could map the officers array. Get the object with the same id in searchAndChangeFor using find. Merge them using spread syntax

If you just want to merge, you could just do

return { ...item, ...searchAndChangeFor.find(o => o.id === item.id) } 

But, if you want to add new properties when a match is found, you can conditionally return like below:

const officers=[{id:20,name:'Captain Piett'},{id:24,name:'General Veers'},{id:56,name:'Admiral Ozzel'},{id:88,name:'Commander Jerjerrod'}],
    searchAndChangeFor = [{id:56,name:'New Name',additionalData:1},];
    
const output = officers.map(item => {
  const found = searchAndChangeFor.find(o => o.id === item.id);
  if (found)
    return { ...item, ...found, newProperty: 'value' }
  else
    return item;
})

console.log(output)

Another option is to clone the officers array to avoid mutation and loop through the searchAndChangeFor instead (since it is the smaller array)

const officers=[{id:20,name:'Captain Piett'},{id:24,name:'General Veers'},{id:56,name:'Admiral Ozzel'},{id:88,name:'Commander Jerjerrod'}],
    searchAndChangeFor = [{id:56,name:'New Name',additionalData:1},],
    output = [...officers];

searchAndChangeFor.forEach(s => {
  const index = officers.findIndex(o => o.id === s.id);
  output[index] = Object.assign({}, output[index], s)
})

console.log(output)

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

5 Comments

I would like to be able to modify matched element beyond searchAndChangeFor. For example, I added additionalData. I want to add more property when I found matched element. Nina's solution find its and modify on-the-fly. Also, array is huge in real-world. I do not want to clone it. (But i guess second approach is best due to search is small)
The output has additionalData. If you want to add more properties, you can add after the find spread. { ...item, ...searchAndChangeFor.find(o => o.id === item.id), anotherProperty: "value" }
But that will add to all elements or just matched element?
@Pratha then you'd have to use ternary operator on find. Also, are you okay with mutation of officers array using forEach? Or do you want new array without modifying officers?
@Pratha updated the first snippet to add new properties when match is found
1

You could find the item and change with the found name or return the item without change.

const
    officers = [{ id: 20, name: 'Captain Piett' }, { id: 24, name: 'General Veers' }, { id: 56, name: 'Admiral Ozzel' }, { id: 88, name: 'Commander Jerjerrod' }],
    searchAndChangeFor = [{ id: 56, name: 'New Name', additionalData: 1 }],
    result = officers.map((item) => {
        let temp = searchAndChangeFor.find((item2) => item.id === item2.id); 
        return temp ? { ...item, name: temp.name } : item;
    });

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Comments

1

find is expecting a boolean response, when it receives true it returns the item that true was returned for, you are attempting to mutate the item directly in the find callback body. This isn't what you need to do, you want to just change the value where the id exists in your searchAndChangeFor for array.

const ids = searchAndChangeFor.map((rel) => rel.id);
const changed = officers.map((item) => ids.includes(item.id) ?
    {{ Item mutation logic here }} :
    item);

Comments

1

Assuming you want to preserve all properties of the objects of officers and searchAndChangeFor:

const officers = [
    { id: 20, name: 'Captain Piett' },
    { id: 24, name: 'General Veers' },
    { id: 56, name: 'Admiral Ozzel', admiralSince: 2008 },
    { id: 88, name: 'Commander Jerjerrod' }
];

const searchAndChangeFor = [
    { id: 56, name: 'New Name', additionalData: 1 },
];

const newOfficers = officers.map(officer => {
    const changedOfficer = searchAndChangeFor.find(changedOfficer => changedOfficer.id === officer.id)
    return changedOfficer ? { ...officer, ...changedOfficer } : officer;
});

console.log(newOfficers);

Comments

0

The issue with your code is that .map expects you to return a value to be stored in the resulting array, whereas you are not returning anything.

You can keep an array of all the ids of searchAndChangeFor. This will be computed only once so it will be efficient, and will be easier to compare with the officer.id in the .map.

const officers = [
  { id: 20, name: 'Captain Piett' },
  { id: 24, name: 'General Veers' },
  { id: 56, name: 'Admiral Ozzel' },
  { id: 88, name: 'Commander Jerjerrod' }
];

const searchAndChangeFor = [
  { id: 56, name: 'Admiral Ozzel' },
];

const allIDsToChange = searchAndChangeFor.map(el => el.id);
const newOfficers = officers.map((item) => allIDsToChange.includes(item.id) ? { ...item,
  name: 'Change name for 56'
} : item);

console.log(newOfficers);

Comments

-2

you can find the item and if found change the name and return the changed item or return item simply (without change)

officers.map((item) => {
   searchAndChangeFor.find((item2) => {
       if (item.id === item2.id) {
          return { ...item, name: 'Change name for 56' } 
       }
   }) || item; 
});

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.