4

i have two arrays like this. first array is customFields and length is 2

var customFields = [  
   {  
      "$$hashKey":"object:259",
      "fields":[  

      ],
      "id":0.84177744416334,
      "inputType":"number",
      "labelShown":"item",
      "type":"textBox",
      "value":"222222"
   },
   {  
      "$$hashKey":"object:260",
      "fields":[  
         "as",
         "dd",
         "asd"
      ],
      "id":0.51091342118417,
      "inputType":"",
      "labelShown":"labels",
      "type":"selectBox",
      "value":"dd"
   }
]

second one is field and length is 3

var field = [  
   {  
      "fields":[  

      ],
      "id":0.84177744416334,
      "inputType":"number",
      "labelShown":"item",
      "type":"textBox"
   },
   {  
      "fields":[  
         "as",
         "dd",
         "asd"
      ],
      "id":0.51091342118417,
      "inputType":"",
      "labelShown":"labels",
      "type":"selectBox"
   },
   {  
      "fields":[  

      ],
      "id":0.32625015743856,
      "inputType":"text",
      "labelShown":"sample",
      "type":"textBox"
   }
] 

both arrays are dynamic and i need to compare these arrays by id fields and add missing objects to customFields array from field array. how can i do this without 2 for loops looping inside one another. what is the most efficient way. thank you !!!!

Sachila Ranawaka
  • 39,756
  • 7
  • 56
  • 80
  • 1
    Basicly you can't achieve this with a single iterator. No matter which iteration feature you're going to use, you always will need nested methods to iterate a nested structure. – Teemu Jan 25 '17 at 10:59
  • Are the objects always in the same order? – cbass Jan 25 '17 at 11:01
  • As i expected, map and reduce answers are coming... :) Anyway, one way or another, you will have loops, under the hood. Nothing wrong with two ordinary, explicite, loops, imho. :) – sinisake Jan 25 '17 at 11:05
  • thing is arrays can contain large no of object and i'm worried comparing and adding objects one a another take some significant time – Sachila Ranawaka Jan 25 '17 at 11:13
  • Try to use [lodash](https://lodash.com), `_.merge` can do this, or you can combine with `_.uniqBy`. – emaniacs Jan 25 '17 at 11:23

3 Answers3

7

You can use reduce() and find() to get desired result.

var customFields = [{"$$hashKey":"object:259","fields":[],"id":0.84177744416334,"inputType":"number","labelShown":"item","type":"textBox","value":"222222"},{"$$hashKey":"object:260","fields":["as","dd","asd"],"id":0.51091342118417,"inputType":"","labelShown":"labels","type":"selectBox","value":"dd"}];
var field = [{"fields":[],"id":0.84177744416334,"inputType":"number","labelShown":"item","type":"textBox"},{"fields":["as","dd","asd"],"id":0.51091342118417,"inputType":"","labelShown":"labels","type":"selectBox"},{"fields":[],"id":0.32625015743856,"inputType":"text","labelShown":"sample","type":"textBox"}]

var result = field.reduce(function(r, e) {
  var f = customFields.find(el => e.id == el.id)
  r.push(f ? f : e)
  return r;
}, [])

console.log(result)
Nenad Vracar
  • 118,580
  • 15
  • 151
  • 176
  • thanks bro. if i understand correctly total and current value passed from reduce method. but can u clarify what happen inside `find` method – Sachila Ranawaka Jan 25 '17 at 11:58
  • Sure, it is looking for element in customFields that has same id as current element in field or `e`. And if it finds it it returns that element or in this case its object – Nenad Vracar Jan 25 '17 at 12:05
  • nice. this is the first time i seen `=>` operator used to assign value in javascript. well first time for everything – Sachila Ranawaka Jan 25 '17 at 12:08
  • That is ES6 arrow function, you can change that with regular function https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions – Nenad Vracar Jan 25 '17 at 12:10
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/133975/discussion-between-sachila-ranawaka-and-nenad-vracar). – Sachila Ranawaka Jan 25 '17 at 12:14
1

You can use native higher order functions such as map and reduce.

Sample implementation using lodash is here. https://github.com/rbs392/object-deep-diff/blob/master/index.js

Balaji V
  • 918
  • 3
  • 10
  • 28
0

Here's a solution without nested loops. First a lookup table is produced containing ID's of the customFields array. Next the field array is traversed and each missing object is appended to customFields array. Lookup table is also updated to take care of possible duplicates.

var lut = customFields.map(function(obj) {
  return obj.id;
});
field.forEach(function(obj) {
  if (lut.indexOf(obj.id) == -1) {
    customFields.push(obj);
    lut.push(obj.id);
  }
});

As noted in comments, my first proposition hid complexity in indexOf.

Here's an alternative approach that relies on object properties for ID lookup, which is likely better than linear search. lut maintains an association from ID to customFields array index.

var lut = customFields.reduce(function(t, obj, i) {
  t[obj.id] = i;
  return t;
}, {});
field.forEach(function(obj) {
  if (undefined === lut[obj.id]) {
    lut[obj.id] = customFields.push(obj) - 1;
  }
});
Joe
  • 1,656
  • 11
  • 10
  • What if customFields is larger than fields...? – Legends Jan 25 '17 at 11:22
  • OP didn't specify the case. This just adds _missing_ entries to `customFields`, regardless of whether there's entries in `customFields` that don't exists in `field` array. – Joe Jan 25 '17 at 11:29
  • 1
    `indexOf` is the nested iteration in this code ; ). – Teemu Jan 25 '17 at 13:56