# Array manipulation - build a new array based on the input from 3 arrays

**URL:** <https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336>\
**Category:** General\
**Created:** [8 May 2020 21:16 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336 "2020-05-08T21:16:02Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![krzydec](https://avatars.discourse-cdn.com/v4/letter/k/a5b964/32.png) [@krzydec](https://discourse.nodered.org/u/krzydec)\
**Post date:** [8 May 2020 21:16 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/1 "2020-05-08T21:16:03Z")

</div>

Hello

I have 2 arrays returned from the two SQL servers. I would like to build a new array I will feed to the dashboard table which will show the comparison between result of the queries.

I get to the point where I create a 3rd array which is a list of results without duplicates and two arrays formatted to the same structure.

Code below from the moment when 3 arrays are formatted:

```auto
var arr = [];
var obj_arr = [{"process":"A"},{"process":"B"},{"process":"C"},{"process":"D"}];
var arr1 = [{"process":"C","qty":88,"origin":"MMS"},{"process":"B","qty":11,"origin":"MMS"},{"process":"A","qty":8,"origin":"MMS"}]
var arr1_length = arr1.length;
var arr2 = [{"process":"A","qty":280,"origin":"SP"},{"process":"D","qty":6,"origin":"SP"},{"process":"C","qty":9,"origin":"SP"}]
var arr2_length = arr2.length;

//Sort arr1 (results are sorted on SQL, but I want this to be future proof)
arr1.sort(function(a, b){
  var x = a.process.toLowerCase();
  var y = b.process.toLowerCase();
  if (x < y) {return -1;}
  if (x > y) {return 1;}
  return 0;
});

//Sort arr2
arr2.sort(function(a, b){
  var x = a.process.toLowerCase();
  var y = b.process.toLowerCase();
  if (x < y) {return -1;}
  if (x > y) {return 1;}
  return 0;
});

//assign values from arr1 to "processes" from obj_arr
var arr3 = obj_arr.map((item, i) => Object.assign({}, item, arr1[i]));
//truncate to arr1_length
arr3 = arr3.slice(0,arr1_length);

//assign values from arr2 to "processes" from obj_arr
var arr4 = obj_arr.map((item, i) => Object.assign({}, item, arr2[i]));
//truncate to arr2_length
arr4 = arr4.slice(0,arr2_length);

obj_arr.forEach(BuildList); //build list of processes

var process;
var arr3qty;
var arr4qty;
var z = 0;

function BuildList (obj_arr,z,arr3,arr4) {
    for (i=0; i < obj_arr.length; i++) {
        if (obj_arr.process == arr3.process){
            arr3qty = arr3.qty;
        } else {
            arr3qty = "test1" // change to null after tetsing;
          }
        if (obj_arr.process == arr4.process){
            arr4qty = arr4.qty;
        } else {
            arr34ty = "test2" // change to null after tetsing;
          }
    }
    process = obj_arr.process;
    arr[z]=[z+1,process, arr3qty, arr4qty]; // build an array
    z = z+1;
    msg.payload = arr;
}

/*
Expected Structure: 
[[1,"A",arr3.qty, arr4.qty],[2,"B",arr3.qty, arr4.qty],[3,"C",arr3.qty, arr4.qty],[4,"D",arr3.qty, arr4.qty]]
Expected Output:
[[1,"A",8,280],[2,"B",11,null],[3,"C",88,9],[4,"D",null,6]]
Actual Output:
[[1,"A",null,null],[2,"B",null,null],[3,"C",null,null],[4,"D",null,null]]
*/

msg.obj_arr = obj_arr;
msg.arr1 = arr1;
msg.arr2 = arr2;
msg.arr3 = arr3;
msg.arr4 = arr4;
return msg;

```

Please can somebody help me with getting _function_ _BuildList_ working.  
What I'm trying to achieve there is to use _obj\_arr_ as a list, which will finally be displayed in the 2nd column of the table and assign corresponding values from the arr3 and arr4.

I know that the _if else_ statements of the function doesn't work, but I don't know why.

I should mention I'm fairly new to programming.

Example of the table I want to build:  
 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/d/c/dc9c0cf3a6674432e90151cd52d788463d597c28.png)

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [8 May 2020 22:01 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/2 "2020-05-08T22:01:07Z")

</div>

Make 1 array - then sort.

E.g.

```auto
var arrays = [...arr1, ...arr2];
arrays.sort(function(a, b){
  var x = a.process.toLowerCase();
  var y = b.process.toLowerCase();
  if (x < y) {return -1;}
  if (x > y) {return 1;}
  return 0;
});

```

---

<div class="post-metadata">

**Author:** ![krzydec](https://avatars.discourse-cdn.com/v4/letter/k/a5b964/32.png) [@krzydec](https://discourse.nodered.org/u/krzydec)\
**Post date:** [8 May 2020 22:44 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/3 "2020-05-08T22:44:35Z")

</div>

Hello

Thank you for your response, but proposed solution is not giving me a structure I'm looking for.  
It leaves me with the same problem that I have to loop through the 1st array to make a _list_ and then loop through 2nd array to _assign_ values to the list.

Your solution output:

```auto
[{"process":"A","qty":8,"origin":"MMS"},{"process":"A","qty":280,"origin":"SP"},{"process":"B","qty":11,"origin":"MMS"},{"process":"C","qty":88,"origin":"MMS"},{"process":"C","qty":9,"origin":"SP"},{"process":"D","qty":6,"origin":"SP"}]

```

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [9 May 2020 07:48 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/4 "2020-05-09T07:48:58Z")

</div>

Yeah, i didnt fully read your post (I assumed you had the final formatting & was demonstrating a simple means of merging)

No matter - this is one (not so elegant) solution...  
NOTE: rather than sort, I use your first array in `obj_arr` to position the final array elements. Means you can order them in any format you wish & also, as a bonus, it filters out any `process` NOT in that array.

```auto

var obj_arr = [{"process":"A"},{"process":"B"},{"process":"C"},{"process":"D"}];
var arr1 = [{"process":"C","qty":88,"origin":"MMS"},{"process":"B","qty":11,"origin":"MMS"},{"process":"A","qty":8,"origin":"MMS"}]
var arr2 = [{"process":"A","qty":280,"origin":"SP"},{"process":"D","qty":6,"origin":"SP"},{"process":"C","qty":9,"origin":"SP"}]

/** convert array to object using key as the - key! */
const arrayToObject = (array, key) => {
  const initialValue = {};
  return array.reduce((obj, item) => {
    item.SP = item.origin == "SP" ? item.qty : null; //set this items SP to qty if the process=="SP"
    item.MMS = item.origin == "MMS" ? item.qty : null; //set this items MMS to qty if the process=="MMS"
    return {
      ...obj,
      [item[key]]: item,
    };

  }, initialValue);
};

/** merge 2 objects recursively */
const merge = (obj1,obj2) => {
    var obj3 = {};
    for (var attrname in obj1) { 
        obj3[attrname] = obj1[attrname]; 
    }
    for (var attrname in obj2) {
        if(obj3[attrname] != null && typeof obj2[attrname] === "object" && typeof obj3[attrname] === "object"){
            obj3[attrname] = merge(obj3[attrname], obj2[attrname]);
        }
        if(obj3[attrname] == null){
            obj3[attrname] = obj2[attrname];
        }  
    }
    return obj3;
};

msg.arr1 = arr1;//add to msg to view in debug output
msg.arr2 = arr2;//add to msg to view in debug output
var arr1obj = arrayToObject(arr1, "process" ); //convert the array to object using 'process' as the key
var arr2obj = arrayToObject(arr2, "process" ); //convert the array to object using 'process' as the key

msg.arr1obj = arr1obj; //add to msg to view in debug output 
msg.arr2obj = arr2obj; //add to msg to view in debug output

//next merge the 2 obexts
msg.merged = merge(msg.arr1obj,msg.arr2obj);

//lastly, generate an array from the merged object
msg.finalArray = [];
//sort and filter based on objects in obj_arr
for(let x = 0; x < obj_arr.length; x++){
    const process = obj_arr[x].process;
    let item = msg.merged[process];
    if(item){
        let el = [
             msg.finalArray.length+1, //index
             process,// A/B/C/D etc
             item.MMS, // MMS qty
             item.SP //SP qty
        ];
        msg.finalArray.push(el)    
    }
}

return msg;

/*
Expected Structure: 
[[1,"A",arr3.qty, arr4.qty],[2,"B",arr3.qty, arr4.qty],[3,"C",arr3.qty, arr4.qty],[4,"D",arr3.qty, arr4.qty]]
Expected Output:
[[1,"A",8,280],
 [2,"B",11,null],
 [3,"C",88,9],
 [4,"D",null,6]]
 Actual Output:
 [[1,"A",8,280],
  [2,"B",11,null],
  [3,"C",88,9],
  [4,"D",null,6]]
*/

```

Proof...

 ![image](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/3X/4/e/4e615dc773ab18a937964dc32afa4e32d8bd4d90.png)

---

<div class="post-metadata">

**Author:** ![krzydec](https://avatars.discourse-cdn.com/v4/letter/k/a5b964/32.png) [@krzydec](https://discourse.nodered.org/u/krzydec)\
**Post date:** [11 May 2020 07:25 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/5 "2020-05-11T07:25:02Z")

</div>

This is working great.  
Thank you for your help.

Please can you explain how the part of the code commented `/** merge 2 objects recursively */` works.  
My understanding is that you set `const merge` and then create function using `=>` notation. Function accepts `obj1, obj2` as arguments and return `obj3`. Than you declare `obj3` as and object within function scope.  
I don't know what `attrname ` is and why `for (var attrname in obj1)` and `for (var attrname in obj2)` will return `true` and what `obj1[attrname]` will look like.  
I searched for `attrname` and the closest find was about the `.attr()` function which returns attribute value, but the syntax is different. I will appreciate if you can point me in the right direction to understand this part.

---

<div class="post-metadata">

**Author:** ![Steve-Mcl](https://sea2.discourse-cdn.com/flex026/user_avatar/discourse.nodered.org/steve-mcl/32/4826_2.png) [@Steve-Mcl](https://discourse.nodered.org/u/Steve-Mcl)\
**Post date:** [11 May 2020 07:48 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/6 "2020-05-11T07:48:50Z")

</div>

> [@krzydec](#):
>
> Please can you explain how the part of the code commented `/** merge 2 objects recursively */` works.

Recursion is a common technique for scaning nested objects. since an array is an object and your original arrays held several objects it was necessary to recursively scan the array in order to turn it from an array of objects into an object of objects.

recursion is quite difficult to explain and quite difficult to visualise but essentially the recursive function calls itself until it has completely scanned all objects and child objects.

A little bit like inception 😉

> [@krzydec](#):
>
> I don't know what `attrname ` is and why `for (var attrname in obj1)` and `for (var attrname in obj2)` will return `true` and what `obj1[attrname]` will look like.

Firstly, attrname is just a local made up variable.

Essentially `for (var attrname in obj1) ` runs through the properties & retuns each key e.g. "process" in `attrname` then "qty" in `attrname` etc.

This allows me to then access the child object properties dynamically, (by name) using square bracket notation

E.g in a loop I can't use hard coded references like `obj1.process` or `obj2.qty` I need to get the child properties specified in the value of `attrName`  
Using `obj1[attrname]` is how we do this in JavaScript.

This is known as property access, square bracket notation. [Here](https://www.tutorialrepublic.com/faq/how-to-dynamically-access-object-property-using-variable-in-javascript.php) is a decent explanation.

If you want to fully understand the code, look at the various objects stored in the msg to see how each stage of the code transforms your data up to the point finalArray is created.

Hope that helps.

~~Ps, I haven't proof read the above as I'm on mobile - hopefully it makes some sense.~~

Should read a bit better now 🙂

---

<div class="post-metadata">

**Author:** ![system](https://us1.discourse-cdn.com/flex026/uploads/nodered/original/1X/d073cd938eafa2e558d7c2cd59003b3ef4963033.png) [@system](https://discourse.nodered.org/u/system)\
**Post date:** [25 May 2020 07:48 UTC](https://discourse.nodered.org/t/array-manipulation-build-a-new-array-based-on-the-input-from-3-arrays/26336/7 "2020-05-25T07:48:51Z")

</div>

Closed on 25 May 2020 07:48 UTC

This topic was automatically closed 14 days after the last reply. New replies are no longer allowed.
