7

My initial state is like below and if new Book added or price is changed then new updated array is coming from service whose result i need to merge in my initial state.

const initialState = {
  booksData: [
    {"Code":"BK01","price":"5"},
    {"code":"BK02","price":"30"},
    {"code":"BK03","price":"332"},
    {"code":"BK04","price":"123"}
  ] 
};

Updated array from server with few records updated/new

data: [
  {"Code":"BK01","price":"10"},
  {"code":"BK02","price":"25"},       
  {"code":"BK05","price":"100"}
] 

updated state should become after merging updated array with old array.

booksData: [
  {"Code":"BK01","price":"10"},
  {"code":"BK02","price":"25"},
  {"code":"BK03","price":"332"},
  {"code":"BK04","price":"123"},
  {"code":"BK05","price":"100"}
] 
1
  • 2
    Keep in mind you are not "merging" arrays, you are creating a brand new array. It's an important distinction. Commented Jan 11, 2018 at 13:56

4 Answers 4

9

I would filter out elements of the old data that are in the new data, and concat.

const oldBooks = booksData.filter(book => !newData.some(newBook => newBook.code === book.code));
return oldBooks.concat(newData);

Keep in mind you must NOT push values into the old array. In your reducer you MUST create new instances, here a new array. 'concat' does that.

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

3 Comments

Does this mutate state?
Array.filter also returns a new array. You can just push the newData. No need to use concat. developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/…
immutability is a state of mind :) use it everywhere, all your code is gonna be easier to read/maintain
3

You can first merge both the array together and then reduce it to remove duplicates like

var booksData = [
   {"code":"BK01","price":"5"},
   {"code":"BK02","price":"30"},
   {"code":"BK03","price":"332"},
   {"code":"BK04","price":"123"}
   ] 

var newData = [
   {"code":"BK01","price":"10"},
   {"code":"BK02","price":"25"},       
   {"code":"BK05","price":"100"}
   ] 

const result = [...newData, ...booksData].reduce((res, data, index, arr) => {
  if (res.findIndex(book => book.code === data.code ) < 0) { 
      res.push(data);

  }  
  return res;
}, [])

console.log(result);

4 Comments

you can also write the condition like this: if(!~res.findIndex(book => book.code === data.code )). just saying :)
@Sagivb.g, Thanks for the suggestion, but I prefer it this way, its easier to understand :)
if readability is your concern then i think Array.prototype.includes is way more readable and easy to understand. :)
@Galupuf yup! i mixed it up with Array.prototype.some(). my bad :) if (!res.some(book => book.code === data.code ))
0

Merge the two array and filter using 'Code' property

const initialState = {
    booksData: [
        { "Code": "BK01", "price": "5" },
        { "code": "BK02", "price": "30" },
        { "code": "BK03", "price": "332" },
        { "code": "BK04", "price": "123" }
    ]
};

const data =
[
    { "Code": "BK01", "price": "10" },
    { "code": "BK02", "price": "25" },
    { "code": "BK05", "price": "100" }
]


let newState = [...initialState.booksData, ...data];
newState = newState.filter((obj, pos, arr) => {
    return arr.map(mapObj => mapObj['Code']).indexOf(obj['Code']) !== pos;
});
console.log(newState);

Comments

0

Collection of Objects

Filter a merged array to pick only non-existent items by iterating every item in the merged array which its index is before the current index of the "parent" filter iterator

const mergedUnique = [
    ...[{id:1}, {id:2}, {id:3}], 
    ...[{id:1}, {id:4}, {id:2}]
  ]
  .filter((item, idx, arr) => 
    !arr.some(({id}, subIdx) => subIdx < idx && id == item.id) 
  )

console.log( mergedUnique )

Basic technique for "simple" arrays

Merge some arrays and filter them to pick only non-existent items by checking if the same item exists anywhere before the current item's index in the merged array.

lastIndexOf is used to check backwards, if the current value exists already, which contributes to keeping the order of the merged array in a certain way which might be desirable, which can only be achieved by checking backward and not forward.

Skip checking the first item - is obviously not a duplicate.

const mergedUniqe = [...[1,2,3], ...[1,3,4,5,2]] // [1, 2, 3, 1, 3, 4, 5, 2]
  .filter((item, idx, arr) => 
    !~arr.lastIndexOf(item, idx-1) || !idx
  )
    
console.log( mergedUniqe )

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.