Creating nested array automatic

Hi,

I'm trying to create a nested array but i don't know the length of the MainArray.

for example:

MainArray[0] = ArrayNest0[ ];
MainArray[1] = ArrayNest1[ ]; 

MainArray[i]= ArrayNesti[ ]

I can create the Array i want if i know the length of the MainArray. I thought of making a case function where i fill in all the different ArrayNest on the basis of which MainArray i need to fill.
But with this methode i need to make alot of var ArrayNest and to be safe, because i need to make sure that i have more then i need.

So my question! Is it possible to create the extra var ArrayNest[ ] automatically when i need them (without declaring them first). Or make the ArrayNest[ ] also variable, something like ArrayNest($i)[ ] with i the extra variable?

Or maybe a better way too approach this problem?

I hope i make some sense. Because i found it hard to explain :sweat_smile:

Thanks at advance!
Kind regards,
Ward

There are many javascript properties and methods for working with arrays. Here is a simple example of length and push.

var fruits = [["Banana", "Orange"], ["Apple", "Mango"]];
fruits[fruits.length] = ["grape", "peach"];
fruits.push(["Kiwi","pear"]);
msg.payload = fruits;
return msg;

@E1cid thanks for the reply.

If i use the push function i need somthing like this:

msg.startdate = new Date();
var entries = Object.entries(msg.payload);
var entrieslength = entries.length;

var MainArray = [[]];
var PushArray = [];

var i;
var i2 = 0;
var n;
var FirstScan = 0;
var Topic;

for (i=0; i!==10; i++) {
    
    Topic = entries[i][0].split("$");
    
    if (FirstScan === 0) {
        PrevTopic = Topic[0];
        firstscan = 1;
        MainArray[i2][].push(['Parameters','Actual Value','Prev Value','Date Changed','Comment']);
    }
    
    if (Topic[0] !== PrevTopic) {
        i2++;
        MainArray[i2][].push(['Parameters','Actual Value','Prev Value','Date Changed','Comment']);
        PrevTopic = Topic[0];
    }
    
    MainArray[i2][].push([Topic[0],entries[i][1],Math.random(),new Date(),Topic[1]]);
}

msg.payload = MainArray;
return msg;

But the problem is Javascript doen't know that syntax that
MainArray[i2][].push()

I tried it with this approach and it works.

var MainArray = [[]];
var PushArray0 = [];
var PushArray1 = [];

MainArray[0] = PushArray0;
MainArray[1] = PushArray1;
MainArray[i] = PushArrayi;

As you can see for every MainArray[i][j] i value i need a new PushArray because i tried it with 1 PushArray and every line in the MainArray gets the same value of the latest PushArray.
What i find strange! Because i thought that if you store a value in MainArray[0] it's saved in that Array on that spot and if i write the second place or any other the value stored in spot 0 doesn't look back at the var that stored it (if that make sense). I don't have the original code anymore i will try to recreate it and send it over.

That's why my original question (which was a little chaotic) was if i could make of the PushArray(i) variable so the code could be alot smaller like example:

var MainArray = [[]];
var PushArray($j) = [];
var i;
var j;

MainArray[i].push(PushArray($j));

or

var MainArray = [[]];
var PushArray(1) = [];
var PushArray(2) = [];

var PushArray(n) = [];
var i;
var j;

if (j<=n) MainArray[i].push(PushArray($j));

For push you provide a reference to the array to which you want to push, so that should be
MainArray.push([...])
or, if you have an already constructed array you want to add, then
MainArray.push(pushArray)

Also your declaration of MainArray should be
var MainArray = []
as it is an array to which you are going to push contained arrays.

The convention in javascript is to start variables with a lower case letter, so if you want to adopt the convention then mainArray would be better.

1 Like
var MainArray =[];
\\ to add to this array
MainArray.push(["an array"]);
\\ this will add an arry element at the end of MainArray

\\to add to a nested array
MainArray[2].push(["something"]);
\\ this wiill add an element to element 2 of MainArray

@Colin @E1cid Thanks for the info with your explanation i found what i did wrong.

My code is here for the ones interested

msg.startdate = new Date();
var entries = Object.entries(msg.payload);
var entrieslength = entries.length;

msg.entries = entries;

var pushArray = [];
var dataArray = [];

var i;
var firstScan = 0;
var topic;
var prevTopic = 0;
var dataLength;


for (i=0; i!==entries.length; i++) {
    
    topic = entries[i][0].split("$");
    
    msg.topic0 = topic[0];
    msg.topic1 = topic[1];
    msg.prevtopic = prevTopic;
    
    if (firstScan === 0) {
        prevTopic = topic[0];
        firstScan = 1;
        dataArray.push(['Parameters','Actual Value','Prev Value','Date Changed','Comment']);
        i1++;
        msg.i1 = i1;
    }
    
    if (topic[0] !== prevTopic) {
        pushArray.push([dataArray]);
        datalength = dataArray.length;
        dataArray = dataArray.splice(0,dataLength);
        dataArray.push(['Parameters','Actual Value','Prev Value','Date Changed','Comment']);
        prevTopic = topic[0];
    }
    dataArray.push([topic[0],entries[i][1],Math.random(),new Date(),topic[1]]);
}
pushArray.push([dataArray]);
msg.payload = pushArray;
return msg;

Does that do what you want, several aspects look a bit odd? Have you looked carefully at what comes out and checked it is ok?

For example, as far as I can see dataArray gets one or more elements added to it each time round the loop, so it is continually getting bigger. Also each time round, if topic[0] !=== prevTopic you push an element onto pushArray. which is an array of one element, where that element is dataArray. But since dataArray is itself getting longer each time you keep adding the same data again, plus a bit more. Then at the end you push dataArray, again in a one element array (ie [dataArray]) to pushArray again before returning it in msg.payload.

A couple of minor things, mainArray appears to be redundant, and I think it is preferable to code the for statement as
for (i=0; i<entries.length; i++) {
That makes it much less likely that a minor code error will cause a (virtually) endless loop.
You might find that the code would be simplified if you used for .. in along with hasOwnProperty rather than Object.entries.
I think msg.i1 will allways be 1, but I may be missing something.
Finally, does it matter which order the properties are enumerated? The order of property enumeration is not guaranteed.

@Colin

My output is:
image

It does it job but if i can simplied it all the better. 1 thing i was looking into.
The dataArray was put in a extra array so if i need to collect the right Setpoints by example:
P2.0-Setpoints (see picture) i need to select msg.payload = pushArray[1][0]

And for the rest
mainArray was indeed redundant. Thought originally that i needed it and forgot to delete it. And the msg.i1 and msg.i2 was for debug purpuses. But i edited the previous post so that's is gone.

And i didn't know of the for .. in function. Definitely going to look into it.

Kind regards
Ward

Notice how each element of the payload array is itself an array of 1 element, which contains the data you want. You can remove the array[1] level by changing the pushArray.push([dataArray]) statements to pushArray.push(dataArray).

The incantation to use with for .. in is something like

for (const prop in msg.payload) {
  if (msg.payload.hasOwnProperty(prop)) {
    // prop now contains the key of one of the properties of the payload
    // and the value of the property is msg.payload[prop]
    // so for example if the payload included  someprop: 73 then prop would be
    // "someprop*  and msg.payload[prop] would be 73
  }
}

The reason for using hasOwnProperty is that the object in msg.payload might contain properties that are actually part of some underlying object that the payload object is derived from. Using hasOwnProperty ensures you only get properties that are part of the top level object.

This was indeed the problem, thanks.

for the For ... in i going to adress it now.

But a followup question. Later in the flow i want to alter some values in the Array.

First i take 2 copies (msg.payload1 & msg.payload2) of the mainArray (see earlier post) which i have put in msg.parametersRead.

But if i now change some values. It's change the values of the both copies and the original. See Picture. (I don't show in the picture but msg.parametersRead. is also the same and the original values where different.)

Why are they linked to each other?

PS: Also tried the push function. instead of msg.payload1 = msg.parametersRead;

That is because of the way javascript handles objects. When you assign an object to a variable it doesn't make a copy, it just sets the variable to point to the object in memory, so if you do that and then change the underlying object both variables are still pointing to the same object so they both change. If you want to make a copy (or clone) of the object then you can use
someVar = RED.util.cloneMessage(originalVar)

Oke that make sense then. With the someVar = RED.util.cloneMessage(originalVar) it works like a charm.