0

I have a JavaScript question that involves combining pieces of different arrays.

I have an array of objects below:

"people": [
        {
            "city": "SF",
            "email": "[email protected]",
            "firstName": "Bob",
            "id": "1",
            "lastName": "Smith"
        },
        {
            "city": "Boston",
            "email": "[email protected]",
            "firstName": "Bill",
            "id": "2",
            "lastName": "Anderson"
        },
        {
            "city": "Toronto",
            "email": "[email protected]",
            "firstName": "Ann",
            "id": "3",
            "lastName": "Kline",
        }
]

I also have an array of tag arrays with an id object in each:

[["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]]

The expected output would be:

"people": [
        {
            "city": "SF",
            "email": "[email protected]",
            "firstName": "Bob",
            "id": "1",
            "lastName": "Smith",
            "tags": ["tag 1", "tag 2"]
        },
        {
            "city": "Boston",
            "email": "[email protected]",
            "firstName": "Bill",
            "id": "2",
            "lastName": "Anderson"
        },
        {
            "city": "Toronto",
            "email": "[email protected]",
            "firstName": "Ann",
            "id": "3",
            "lastName": "Kline",
            "tags": ["tag 8", "tag 2"]
        }
]

Is there a way to add the tags to the objects above where the "id"'s match without doing a nested loop. I have tried a couple ways but have failed.

4
  • What is the expected output and show your attempted code. Commented Jun 15, 2021 at 16:00
  • 1
    That is a very odd structure for the second array (having an ID in an object as part of an array), do you have any option to change it, or are these structures out of your control? Commented Jun 15, 2021 at 16:01
  • What do you mean with "without ... a nested loop"? Does this also involve array functions like Array.prototype.map? Commented Jun 15, 2021 at 16:06
  • Thank you for the replies. I have added the structure of how I would like the output would look like. It is a weird structure and ultimately I'm trying too make the tags in the array a "tags" object and combine it with "people" where the id's match. Commented Jun 15, 2021 at 16:08

2 Answers 2

1

You could create a Map object which maps each id with the tags. Loop through the people array and add a property if the Map has the current id as key

const people=[{city:"SF",email:"[email protected]",firstName:"Bob",id:"1",lastName:"Smith"},{city:"Boston",email:"[email protected]",firstName:"Bill",id:"2",lastName:"Anderson"},{city:"Toronto",email:"[email protected]",firstName:"Ann",id:"3",lastName:"Kline",}],
      tags = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]]
      
const map = new Map( tags.map(t => [t.pop().id, t]) )

for (const p of people)
  if (map.has(p.id))
    p.tags = map.get(p.id)

console.log(people)

You can also create a version which doesn't mutate the arrays

const map = new Map;

for (const t of tags)
    map.set( t[t.length - 1].id, t.slice(0, -1) )

const output = people.map(p => ({
    ...p,
    tags: map.get(p.id) ?? []
}));
Sign up to request clarification or add additional context in comments.

2 Comments

very neat, but this will work only if the ID is on the last position right?
@AlbertoSinigaglia OP's code hasn't made any indication that it will be in any other position.
0

Maybe something like this:

let input = [
        {
            "city": "SF",
            "email": "[email protected]",
            "firstName": "Bob",
            "id": "1",
            "lastName": "Smith"
        },
        {
            "city": "Boston",
            "email": "[email protected]",
            "firstName": "Bill",
            "id": "2",
            "lastName": "Anderson"
        },
        {
            "city": "Toronto",
            "email": "[email protected]",
            "firstName": "Ann",
            "id": "3",
            "lastName": "Kline",
        }
]
let toAdd = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]].reduce((acc, el) => {
  // build a object with id -> list of tags
  acc[el.find(o => typeof o === 'object' && o !== null).id] = el.filter(o => !(typeof o === 'object' && o !== null))
  return acc;
}, {})
console.log(input.map(el => {
   // add the tags to el if tags exists
   el.tags = toAdd[el.id] || [];
   return el
}))

this is O(n^2).. if you are certain that your array has always that object at the end, you can have a O(n) with

let input = [
        {
            "city": "SF",
            "email": "[email protected]",
            "firstName": "Bob",
            "id": "1",
            "lastName": "Smith"
        },
        {
            "city": "Boston",
            "email": "[email protected]",
            "firstName": "Bill",
            "id": "2",
            "lastName": "Anderson"
        },
        {
            "city": "Toronto",
            "email": "[email protected]",
            "firstName": "Ann",
            "id": "3",
            "lastName": "Kline",
        }
]
let toAdd = [["tag 1", "tag 2", {"id": "1"}], ["tag 8", "tag 2", {"id": "3"}]].reduce((acc, el) => {
  // build a object with id -> list of tags
  acc[el.pop().id] = el
  return acc;
}, {})
console.log(input.map(el => {
   // add the tags to el if tags exists
   el.tags = toAdd[el.id] || [];
   return el
}))

10 Comments

OP wants to avoid nested loops and this answer has 3 levels of nesting.
You have a find in a reduce in a map. Complexity: O(m * n²). I'm pretty sure there is a solution with O(m + n).
@jabaa not i have a find in a reduce and then a map....and this ends with a O(n^2), not O(n^3), since it has only 2 level of depth
Yes, sorry. You're right. I thought toAdd is a function but it's an object.
@jabaa no, you're wrong, the map is subsequent to the reduce, so it's O(n^2)+O(n)
|

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.