Retrieving item between two arrays of object with complex conditions

Viewed 79

I got two lists of objects :

let list1 = [{id: '1', status: 'use', comment: 'xxxx'}, {id: '2', status: 'ready', comment: 'yyyy'}, {id: '3', status: 'ready', comment: 'zzzz'}];
let list2 = [{uid: '1', elec: 60}, {uid: '2', elec: 60}, {uid: '10', elec: 60}, {uid: '3', elec: 40}];

What i want is to retrieve an object of list2 that have elec > 50 and the same uid than one item id of the list1 only if the item of the list1 have a status == "ready". Also, i want to add to this item the parameter 'comment' from the object of the list1.

In this exemple, my result value would be : {uid: '2', elect: 60, comment: 'yyyy'}.

I did this :

  let list1Filtered = list1.filter(itemList1 => itemList1.status == 'ready');
  let list2Filtered = list2.filter(itemList2 => itemList2.elec > 50);
  var result;

  for ( let  itemList1Filtered of list1Filtered ) {
    for ( let  itemList2Filtered of list2Filtered ) {
      if (!result && itemList1Filtered.id == itemList2Filtered.uid) {
        result = itemList2Filtered;
        result.comment = itemList1Filtered.comment;
      }
    }
  }
  
  return result;

I want to know if there is a more elegant and/or more sophisticated way to do this in Javascript.

6 Answers
let result = {
    ...list2.filter(
    a => a.elec > 50 && a.uid === list1.filter(b => b.status === "ready")[0].id)[0],
    comments: list1.filter(b => b.status === "ready")[0].comment
}

You could collect wanted comments from list1 and reduce list2 with a check for the value of elec and if an item exist from the other list. Then return a new object.

This approach needs only two loops.

const
    list1 = [{ id: '1', status: 'use', comment: 'xxxx' }, { id: '2', status: 'ready', comment: 'yyyy' }, { id: '3', status: 'ready', comment: 'zzzz' }],
    list2 = [{ uid: '1', elec: 60 }, { uid: '2', elec: 60 }, { uid: '10', elec: 60 }, { uid: '3', elec: 40 }],
    l1 = list1.reduce((r, { id, status, comment }) => {
        if (status === 'ready') r[id] = { comment };
        return r;
    }, {}),
    result = list2.reduce((r, o) => {
        if (o.elec > 50 && o.uid in l1) r.push({ ...o, ...l1[o.uid]})
        return r;
    }, []);

console.log(result);

Try this:

let list1 = [
  { id: '1', status: 'use', comment: 'xxxx' },
  { id: '2', status: 'ready', comment: 'yyyy' },
  { id: '3', status: 'ready', comment: 'zzzz' },
];
let list2 = [
  { uid: '1', elec: 60 },
  { uid: '2', elec: 60 },
  { uid: '10', elec: 60 },
  { uid: '3', elec: 40 },
];

let result = null;
let itemFound;

const filteredList = list2.filter((list2Item) => {
  if (!result) {
    itemFound =
      list2Item.elec > 50 &&
      list1.find(
        (list1Item) =>
          list2Item.uid === list1Item.id && list1Item.status === 'ready'
      );
    if (itemFound) {
      result = {
        uid: list2Item.uid,
        elect: list2Item.elec,
        comment: itemFound.comment,
      };
    }
  }
});

console.log(result);

This should do the job:

const list1 = [{
  id: '1',
  status: 'use',
  comment: 'xxxx'
}, {
  id: '2',
  status: 'ready',
  comment: 'yyyy'
}, {
  id: '3',
  status: 'ready',
  comment: 'zzzz'
}];

const list2 = [{
  uid: '1',
  elec: 60
}, {
  uid: '2',
  elec: 60
}, {
  uid: '10',
  elec: 60
}, {
  uid: '3',
  elec: 40
}];

const filteredList = list2.filter(item => {
  const readyItemsList1 = list1.filter(item => item.status === 'ready').map(item => item.id);
  return item.elec > 50 && readyItemsList1.indexOf(item.uid) > -1
}).map(item => {
  const comment = list1.find(it => it.id === item.uid).comment;
  item.comment = comment;
  return item;
});

console.log(filteredList);

you can restructure your data. List1 convert it in object. And now we can find solution in O(n).

let list1 = [{
  id: '1',
  status: 'use',
  comment: 'xxxx'
}, {
  id: '2',
  status: 'ready',
  comment: 'yyyy'
}, {
  id: '3',
  status: 'ready',
  comment: 'zzzz'
}];
let list2 = [{
  uid: '1',
  elec: 60
}, {
  uid: '2',
  elec: 60
}, {
  uid: '10',
  elec: 60
}, {
  uid: '3',
  elec: 40
}];
const itemList = {}
list1.forEach(item => {
  if (item.status === 'ready') {
    itemList[item.id] = item.comment
  }
});
const result = list2.filter(item => itemList[item.uid] && item.elec > 50).map(item => {
  item['comment'] = itemList[item.uid]
  return item
})
console.log(result)

filter and map will help you.

filter can select items fit some criteria, and map let you change the data to pick.

For list1, select item with status equals 'ready', then take only id.

var ready_id_array = list1.filter(item=>item.status == 'ready').map(item=>item.id);

For list2, check item that its uid contained in ready_id_array, and elec larger than 50.

var result = list2 .filter(item => ready_id_array.indexOf(item.uid) > -1 && item.elec > 50);

to append the comment, a dictionary is created and then put comment back to result

var comment_dictionary = list1.reduce((a,x) => ({...a, [x.id]: x.comment}), {});
result.forEach(item => item.comment = comment_dictionary[item.uid]);

and you will have the result.

[{uid: "2", elec: 60, comment: "yyyy"}]
Related