Home > Blockchain >  Return similar values ​from multiple array of objects in Javascript
Return similar values ​from multiple array of objects in Javascript

Time:09-27

Guys I made a simple example to illustrate my problem. I have 3 object arrays, datasOne, datasTwo and datasThree and what I want is to return a new array only with the objects that are in the 3 arrays. For example, if there is only Gustavo in the 3 arrays, then he will be returned. But there is a detail that if the datasThree is an empty array, then it will bring the data in common only from datasOne and datasTwo and if only the datasTwo which has data and the other two arrays have empty, then it will return data only from datasTwo. In other words it is to return similar data only from arrays that have data. I managed to do this algorithm and it works the way I want, but I would like to know another way to make it less verbose and maybe simpler and also work in case I add more arrays to compare like a dataFour for example. I appreciate anyone who can help me.

My code below:

let datasOne = [
  { id: 1, name: 'Gustavo' },
  { id: 2, name: 'Ana' },
  { id: 3, name: 'Luiz' },
  { id: 8, name: 'Alice' }
]

let datasTwo = [
  { id: 1, name: 'Gustavo' },
  { id: 3, name: 'Luiz' },
  { id: 8, name: 'Alice' }
]

let datasThree = [
  { id: 1, name: 'Gustavo' },
  { id: 3, name: 'Luiz' },
  { id: 2, name: 'Ana' },
  { id: 5, name: 'Kelly' },
  { id: 4, name: 'David' }
]

let filtered

if (datasOne.length > 0 && datasTwo.length > 0 && datasThree.length > 0) {
  filtered = datasOne.filter(firstData => {
    let f1 = datasThree.filter(
      secondData => firstData.id === secondData.id
    ).length
    let f2 = datasTwo.filter(
      secondData => firstData.id === secondData.id
    ).length
    if (f1 && f2) {
      return true
    }
  })
} else if (datasOne.length > 0 && datasTwo.length > 0) {
  filtered = datasOne.filter(firstData => {
    return datasTwo.filter(secondData => firstData.id === secondData.id).length
  })
} else if (datasOne.length > 0 && datasThree.length > 0) {
  filtered = datasOne.filter(firstData => {
    return datasThree.filter(secondData => firstData.id === secondData.id)
      .length
  })
} else if (datasTwo.length > 0 && datasThree.length > 0) {
  filtered = datasTwo.filter(firstData => {
    return datasThree.filter(secondData => firstData.id === secondData.id)
      .length
  })
} else if (datasThree.length > 0) {
  filtered = datasThree
} else if (datasTwo.length > 0) {
  filtered = datasTwo
} else if (datasOne.length) {
  filtered = datasOne
}

console.log(filtered)

CodePudding user response:

Not 100% sure it cover all edge cases, but this might get you on the right track:

function filterArrays(...args) {
  const arraysWithData = args.filter((array) => array.length > 0);
  const [firstArray, ...otherArrays] = arraysWithData;

  return firstArray.filter((item) => {
    for (const array of otherArrays) {
      if (!array.some((itemTwo) => itemTwo.id === item.id)) {
        return false;
      }
    }
    return true;
  });
}

Usage:

const filtered = filterArrays(datasOne, datasTwo, datasThree);
console.log(filtered)

I believe the code is fairly readable, but if something is not clear I'm glad to clarify.

CodePudding user response:

1) You can first filter the array which is not empty in arrs.

const arrs = [datasOne, datasTwo, datasThree].filter((a) => a.length);

2) Flatten the arrs array using flat().

arrs.flat()

3) Loop over the flatten array and count the occurrence of all objects using Map

const map = new Map();
for (let o of arrs.flat()) {
  map.has(o.id)
    ? (map.get(o.id).count  = 1)
    : map.set(o.id, { ...o, count: 1 });
}

4) Loop over the map and collect the result only if it is equal to arrs.length

if (count === arrs.length) result.push(rest);

let datasOne = [
  { id: 1, name: "Gustavo" },
  { id: 2, name: "Ana" },
  { id: 3, name: "Luiz" },
  { id: 8, name: "Alice" },
];

let datasTwo = [
  { id: 1, name: "Gustavo" },
  { id: 3, name: "Luiz" },
  { id: 8, name: "Alice" },
];

let datasThree = [
  { id: 1, name: "Gustavo" },
  { id: 3, name: "Luiz" },
  { id: 2, name: "Ana" },
  { id: 5, name: "Kelly" },
  { id: 4, name: "David" },
];

const arrs = [datasOne, datasTwo, datasThree].filter((a) => a.length);

const map = new Map();
for (let o of arrs.flat()) {
  map.has(o.id)
    ? (map.get(o.id).count  = 1)
    : map.set(o.id, { ...o, count: 1 });
}

const result = [];
for (let [, obj] of map) {
  const { count, ...rest } = obj;
  if (count === arrs.length) result.push(rest);
}

console.log(result);
/* This is not a part of answer. It is just to give the output fill height. So IGNORE IT */
.as-console-wrapper { max-height: 100% !important; top: 0; }

CodePudding user response:

function merge(arr){
  arr = arr.filter(item=>item.length>0)
  const map = {};
  arr.forEach(item=>{
    item.forEach(obj=>{
      if(!map[obj.id]){
        map[obj.id]=[0,obj];
      }
      map[obj.id][0]  ;
    })
  })
  const len = arr.length;
  const ret = [];
  Object.keys(map).forEach(item=>{
    if(map[item][0]===len){
      ret.push(map[item][1])
    }
  })
  return ret;
}
merge([datasOne,datasTwo,datasThree])
  • Related