0

This 2 arrays have multiple objects that has the the same ID but different dates

const names= [
{id:'1',name:'a',date:'1604616214'},
{id:'1',name:'Angel',date:'1604616215'},
{id:'2',name:'b',date:'2004616214'},
{id:'2',name:'Karen',date:'2004616215'},
{id:'3',name:'a',date:'3004616220'},
{id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
{id:'1',lastname:'a',date:'4004616220'},
{id:'1',lastname:'Ferguson',date:'4004616221'},
{id:'2',lastname:'b',date:'5004616220'},
{id:'2',lastname:'Nixon',date:'5004616221'},
{id:'3',lastname:'a',date:'6004616222'},
{id:'3',lastname:'Richard',date:'6004616223'}
]

The data is in moment().unix() to create a number "easy to compare"

I want to create a Third array that merge the 2 arrays and create objects with the same id and the last updated date object.

The output should be something like this

const third = [
{id:'1',name:'Angel',lastname:'Ferguson'},
{id:'2',name:'Karen',lastname:'Nixon'},
{id:'3',name:'Erik',lastname:'Richard'}
]

This is what i got so far, if i updated the arrays it duplicates and i need to have only the last updated object

const third = names.map(t1 => ({...t1, ...lastnames.find(t2 => t2.id === t1.id)})) 
7
  • What have you tried so far? Also, improve the code's format. It's hard to read. Commented Nov 5, 2020 at 21:49
  • updated @EmilioGrisolía Commented Nov 5, 2020 at 21:50
  • " names.map" ---> what is "names" object ? where do you define it ? an error is thrown when I try this code. Commented Nov 5, 2020 at 22:40
  • 1
    updated arrays names, sorry @AntiqTech Commented Nov 5, 2020 at 22:41
  • 1
    updated again, improved formatting @AntiqTech Commented Nov 5, 2020 at 22:48

3 Answers 3

1

I'm going to assume since you have the spread operator and Array.find in your example that you can use ES6, which includes for of and Object.values as you see below.

An object and simple looping is used to reduce the amount of times you're iterating. In your example, for every element in names you're iterating over last names to find one with the same ID. Not only is that not ideal for performance, but it doesn't work because every time you're finding the same element with that ID (the first one with that ID in the array).

const names = [
  { id: "1", name: "a", date: "1604616214" },
  { id: "1", name: "Angel", date: "1604616215" },
  { id: "2", name: "b", date: "2004616214" },
  { id: "2", name: "Karen", date: "2004616215" },
  { id: "3", name: "a", date: "3004616220" },
  { id: "3", name: "Erik", date: "3004616221" },
];
const lastnames = [
  { id: "1", lastname: "a", date: "4004616220" },
  { id: "1", lastname: "Ferguson", date: "4004616221" },
  { id: "2", lastname: "b", date: "5004616220" },
  { id: "2", lastname: "Nixon", date: "5004616221" },
  { id: "3", lastname: "a", date: "6004616222" },
  { id: "3", lastname: "Richard", date: "6004616223" },
];

const profiles = {};

function addToProfiles(arr, profiles) {
  for (let obj of arr) {
    if (obj.id != null) {
      // Inits to an empty object if it's not in the profiles objects
      const profile = profiles[obj.id] || {};
      profiles[obj.id] = { ...profile, ...obj };
    }
  }
}

addToProfiles(names, profiles);
addToProfiles(lastnames, profiles);

const third = Object.values(profiles);
Sign up to request clarification or add additional context in comments.

2 Comments

you foKING GENIUS! THANKS BRO!.... correct me if I'm wrong, this arr??? for (let obj of arr) this line empty by default const profile = profiles[obj.id] || {}; This line is the merge profiles[obj.id] = { ...profile, ...obj }; And everytime the function its called, it create/reset the object, correct?
@AlexHunter, profiles is instantiated only the one time. The function is making use of the same variable both times it is called. In terms of "profiles[obj.id] = { ...profile, ...obj };", we are taking the profile object, which is either the previous object in profiles for that ID or an empty object, and merging the data in that object with the current entry we are at in the iteration, overwriting whatever was previously in the object.
1

The idea is to group the objects by their ids, then merge each group according to the rules, maximizing date for each type of record (name and lastname)

// the input data
const names= [
  {id:'1',name:'a',date:'1604616214'},
  {id:'1',name:'Angel',date:'1604616215'},
  {id:'2',name:'b',date:'2004616214'},
  {id:'2',name:'Karen',date:'2004616215'},
  {id:'3',name:'a',date:'3004616220'},
  {id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
  {id:'1',lastname:'a',date:'4004616220'},
  {id:'1',lastname:'Ferguson',date:'4004616221'},
  {id:'2',lastname:'b',date:'5004616220'},
  {id:'2',lastname:'Nixon',date:'5004616221'},
  {id:'3',lastname:'a',date:'6004616222'},
  {id:'3',lastname:'Richard',date:'6004616223'}
]

// make one long array
let allNames = [...names, ...lastnames]

// a simple version of lodash _.groupBy, return an object like this:
// { '1': [ { objects with id==1 }, '2': [ ... and so on ] }
function groupById(array) {
  return array.reduce((acc, obj) => {
    let id = obj.id
    acc[id] = acc[id] || [];
    acc[id].push(obj);
    return acc;
  }, {});
}

// this takes an array of objects and merges according to the OP rule
// pick the maximum date name object and maximum date lastname object
// this sorts and searches twice, which is fine for small groups
function mergeGroup(id, group) {
  let sorted = group.slice().sort((a, b) => +a.date < +b.date)
  let name = sorted.find(a => a.name).name
  let lastname = sorted.find(a => a.lastname).lastname
  return {
    id,
    name,
    lastname
  }
}

// first group, then merge
let grouped = groupById(allNames)
let ids = Object.keys(grouped)
let results = ids.map(id => {
  return mergeGroup(id, grouped[id])
})
console.log(results)

Comments

1

I tried to come up with a solution using filter functions. End result contains the format you wanted. check it out.

const names= [
{id:'1',name:'a',date:'1604616214'},
{id:'1',name:'Angel',date:'1604616215'},
{id:'2',name:'b',date:'2004616214'},
{id:'2',name:'Karen',date:'2004616215'},
{id:'3',name:'a',date:'3004616220'},
{id:'3',name:'Erik',date:'3004616221'}
]
const lastnames= [
{id:'1',lastname:'a',date:'4004616220'},
{id:'1',lastname:'Ferguson',date:'4004616221'},
{id:'2',lastname:'b',date:'5004616220'},
{id:'2',lastname:'Nixon',date:'5004616221'},
{id:'3',lastname:'a',date:'6004616222'},
{id:'3',lastname:'Richard',date:'6004616223'}
]
// filter out last updated objects from both arrays
var lastUpdatednames = names.filter(filterLastUpdate,names);
console.log(lastUpdatednames);
var lastUpdatedsurnames = lastnames.filter(filterLastUpdate,lastnames);
console.log(lastUpdatedsurnames);
// combine the properties of objects from both arrays within filter function.
const third = lastUpdatednames.filter(Combine,lastUpdatedsurnames);
console.log(third);
 
function filterLastUpdate(arrayElement) 
{
    var max =   this.filter( i => arrayElement.id==i.id  ).reduce(
             function(prev, current) 
              {
                return (prev.date > current.date) ? prev : current
               }
           )
        return max.date == arrayElement.date ;
}
function Combine(firstArray) 
{
    
    var subList= this.filter( i => firstArray.id==i.id  );
    //console.log(subList);
    //console.log(subList[0]);
    
    if (subList) 
    { 
       firstArray.lastname = subList[0].lastname;    
       return true;
    }
    return false ;
}

Here is last output:

[…]
0: {…}
date: "1604616215"
id: "1"
lastname: "Ferguson"
name: "Angel"
1: {…}
date: "2004616215"
id: "2"
lastname: "Nixon"
name: "Karen"
2: {…}
date: "3004616221"
id: "3"
lastname: "Richard"
name: "Erik"

5 Comments

Glad you like it and find it useful!
I'm curious. Is there any reason in this case for using var over let? Thanks.
No particular reason really.
Curious is that none create mini courses about this kind of problems. What do you think?
You are right. Even if SOF has solutions for these, it sometimes becomes a bother sift through all those pages to find a solution that fits to your problem. A mini course dealing with certain quick solutions for these would be nice.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.