Manipulate Lists/Array

Hi All,

Just wondering if anyone could help with a question on manipulating a list/array.

An example of what I am trying to do is select a row of building envelope elements or multiple rows based on a variable.

For example selecting every 3rd row or even more complex selecting every 2nd panel on every 4th row.

As a basic example I thought I would start with a line with points and try and create a list that just showed every second point.

So starting with: {point1[0], point1[1], point1[2], point1[3], point1[4], point1[5], point1[6], point1[7]}

And returning: {point1[0], point1[2], point1[4], point1[6]}

I thought I could do it with a point by function node?

So I started testing but with no luck. My final function looked a bit like this:

 

function (Point[] Llist)

{

for (int i = 0; i < Llist.Count; i+=2)

{

Point pList = new Point(this).xxxxxxxxx;

}

Point PPoint = new Point(pList);

}

 

But I am obviously missing something, I tried multiple options in place of the xxxxxxx but with no luck, maybe I am going down the wrong path!

Any tips would be welcome

 

Thanks

Wayne

  • Hi Wayne,

    For a one-dimensional list you could use the list method "MembersAt". If your list is food = {potato, egg, cucumber, broccoli, fish, steak}, then food.MembersAt({1,3,5}) is {potato, cucumber, fish}.

    For multi-dimensional lists, you'd have to iterate through the nested lists; however, instead of recreating the items you want to select you could add them to a list of the type:

    function (Point[][] pntarray, int dRow, int dItem)
    {
        Point returnlist = {};
        for (int i = 0; i < pntarray.Count; i += dRow)
        {
            for (int j = 0; j < pntarray[i].Count; j += dItem)
            {
                returnlist.Add(pntarray[i][j]);
            }
        }
        return returnlist;
    }
    

    This function code would reside in a FunctionCall node (or could be a named Script Function created in and added to the Functions dialog).

    Additional refinements could be to add startRow and startItem and change the loops to start at those values, respectively, i.e. for (int i = startRow; … .

    HTH,

          Volker

       

  • Hi Volker,

    Thanks for the pointers. (insert joke here)

    One thing I overlooked was that I managed to input a 0 value for dRow which puts it into an infinite loop.

    So I add an “if” statement around the loop as a safeguard. I think this is the best way to do it.

    if (dRow > 0 && dItem >0)

     

    I have 2 questions:

    The return list is a flat list rather than an array, so if wanted to use the point as for a Polygon ByPointGrid it will error.

    Is there an easy way to output the results as an array rather than a list?

     

    The second question is if I needed to select 2 or 3 rows of points ever N rows? How would I go about writing a script for this.

    I first thought I would need to find i being the first row of points I needed then adding a variable for the number of rows I needed about this say 3. Then loop again and find the next i and so on.

    I have attached a picture to try and explain. Using this we could alternate façade panels every 3 floors.

    So far I have the following: (which is obviously wrong but starting somewhere :) )

    function (Point[][] pntarray, int dRow, int dItem, int dSpan)
    
    {
    
    Point returnlist = {};
    
    int j=0;
    
    // I believe this int j=0 needs to be within the for loop as it needs to reset for each loop.
    
    if (dRow > 0 && dItem >0)
    
    {
    
        for (int i = 0; i < pntarray[i].Count; i += dRow+j)
    
        //while (j < dSpan) ??
    
            {
    
            for (int k =0; k < pntarray[i].Count; k += dItem)
    
    
            returnlist.Add(pntarray[i][k]);
    
            // j ++; ??
    
            }
    
    }
    
    return returnlist;
    
    }
    
     

    The other approach I had was to select each row separately and then combine them in a ToList expression

    {point1[0],point1[1],point1[2]}.ToList()

    And

    {point1[2],point1[3],point1[4]}.ToList()

    Etc

    And then place combine these back into 1 list with another ToList() which works perfectly for what I need for the output but it feels very manual. I am sure there is a way to achieve this via a script.

    Or alternatively I could have used:

    {point1.Sublist(0,3),point1.Sublist(2,3)}.ToList()

    Which is much more refined, and looking at it you could probably for statement with a increment of 2 and a variable for the count. Maybe this is the best approach for this.

    Any tips would be appreciated

    Thanks
    Wayne

  • Update:

    I think I worked out the second part.

    using the Sublist I could specify the range(count) and return the desired rows of points every Nth spacing

    function (Point[][] pntarray, int dRow, int dSpan)
    {
        Point returnlist = {};
    
        for (int i = 0; i < pntarray.Count; i += dRow)
        {
        returnlist.Add(pntarray.Sublist(i,dSpan));
    
        }
    
        return returnlist;
    }

    actually ended up as a simple function call.

    let me know if you can see any improvements

    Thanks


    Wayne

  • Hi Wayne,

    I had a simple example some days ago concerning a 'correctly' labeled pointlist where Volker showed 'the right way'.

    I think there you can get the solution for your first question.

    Ingo

  • Thanks Ingo,

    I will have a look at that thread.

    For anyone interested in the Second part and a method of placing polygons on alternating or different spacing for I have attached an example file I created to test out my facade options. (work in progress as always :))

    Thanks

    Wayne

    PolyEveryNthFloor.dgn