Filter by Boolean, extracting info from sublists


#1

I have a list of lists containing lines. Each element in the list contains the start and end point xyz’s and the length. I want to extract the longest line in each sublist. If I have a flat list, I know how to do this using the List.Filter node as follows:

ListFilter

 

 

 

 

 

 

I’ve been able to iterate on a list of list using the List.Map node, which took me a while to understand and get the hang of it. I thought I could use a similar technique here, but was not able to as the List.Filter node cannot be passed to List.Map as a function (says it doesn’t recognize an array, but I have been able to pass other arrays with no problems, including arrays from other List.Map nodes! So I’m not sure if this is actually a bug). An approach that sounds reasonable is to be produce a Boolean list of list and then use the List.FilterByBoolMask but I have not been able to produce one of the same dimensions when dealing with a combination of flat lists and nested lists. So for example:

List “X”

[0] List

[0] A0

[1] A1

[2] A2

[1] List

[0] B0

[1] B1

[2] B2

Let’s assume A2 (2m) and B1 (3m) represent the longest lines. I can create a list of these values as follows:

List “Y”

[0] 2

[1] 3

If I use a == node wired to List “X” as a function to List.Map, and wire List “Y”, I end up with a much larger list than List “X”, which is not what I want:

List “L”

[0] List

[0] List

[0]2 A0 (False)

[1] 2A1 (False)

[2]2 A2 (True)

[1] List: *

[0]3 A0 (False)

[1] 3A1 (False)

[2]3A2 (False)

[1] List:

[0] List *

[0]2 B0 (False)

[1] 2B1 (False)

[2]2 B2 (False)

[1] List:

[0]3 B0 (False)

[1] 3B1 (True)

[2]3B2 (False)

The lists shown with an asterisk * are obviously redundant. Is there a way to avoid getting these and only have item [0] in List “Y” compared with List [0] in List “X”, item [1] in List “Y” compared with List [1] in List “X”, etc.? I’m trying to do this without Python as I don’t know squat :slight_smile: But if Python is required, then so be it. Thanks in advance for any help you might offer (sorry for the long post!).


#2

I can’t seem to have any luck formatting the post with tables, so I’ll re-post with images instead since I cannot edit the first post.

I have a list of lists containing lines. Each element in the list contains the start and end point xyz’s and the length. I want to extract the longest line in each sublist. If I have a flat list, I know how to do this using the List.Filter node as follows:

ListFilter

 

 

 

 

 

 

 

 

 

 

 

 

I’ve been able to iterate on a list of list using the List.Map node, which took me a while to understand and get the hang of it. I thought I could use a similar technique here, but was not able to as the List.Filter node cannot be passed to List.Map as a function (says it doesn’t recognize an array, but I have been able to pass other arrays with no problems, including arrays from other List.Map nodes! So I’m not sure if this is actually a bug). An approach that sounds reasonable is to be produce a Boolean list of list and then use the List.FilterByBoolMask but I have not been able to produce one of the same dimensions when dealing with a combination of flat lists and nested lists. So for example:

List X

 

 

 

 

 

 

Let’s assume A2 (2m) and B1 (3m) represent the longest lines. I can create a list of these values as follows:

List Y

 

 

 

If I use a == node wired to List “X” as a function to List.Map and wire List “Y” to the list port, I end up with a much larger list than List “X”, which is not what I want:

List L

 

 

 

 

 

 

 

 

 

 

 

 

 

The lists shown with an asterisk * are obviously redundant. Is there a way to avoid getting these and only have item [0] in List “Y” compared with List [0] in List “X”, item [1] in List “Y” compared with List [1] in List “X”, etc.? I’m trying to do this without Python as I don’t know squat :slight_smile: But if Python is required, then so be it. Thanks in advance for any help you might offer (sorry for the long post!).


#3

Hi,

Have you tried the “MaximumItemByKey” node?

Capture3


#4

Hi Dimitar, no I have not. Thanks a lot for posting, this gets me exactly what I need. However I don’t know how to use that node by itself. Could you kindly post an example?

I managed to find another solution using the List.LaceShortest node to create a Boolean list that I then use with the List.FilterByBoolMask. I’m not sure which method would be the fastest to process, but I figure your example would! Here’s what I did:

List.LaceShortest


#5

Your approach is a perfectly valid one as well. However when speed is concerned, I’ve found out that the less nodes you have, the faster the work-flow will process. Keep in mind that most of the time however, the bottleneck isn’t Dynamo but Revit itself. Less nodes also gives you the chance to debug faster and modify your work-flow more easily.

If your definition is particularly straining and you need every ounce of speed Dynamo can muster, then you should try to write your code using code block nodes. Research from the community has shown that that approach can give you a noticeably faster processing.

Simply put the “List.MaximumItemByKey” takes in a function(in our case the curve’s length) and a list. It then applies the function to the members inside the input list, checks which index of the result is the maximum and then extracts the corresponding index from the input list. So in reality it acts like a three-in-one combo node :slight_smile:


#6

Ahh I see, so basically if you can do it with a code block, it’s preferred over using nodes…interesting. I guess it’s also time to learn Design Script! Kinda defeats the purpose of using nodes though, but if it’s faster, I’ll deal with it that way.

From the examples of list management I’ve seen posted, it really seems that you can do things faster through Python and require a lot less nodes to get it done too. So that will be my next endeavor. In my little project that got me into trying out Dynamo, I really need to reduce the number of objects it processes so lists are much shorter and more manageable. Now that I’m gaining a bit more confidence, I’ll re-do some of my nodes by re-thinking how I get my end result. For exampe right now I’m after finding the direction of specific objects (they are mostly cuboids). I was taking their geometry, exploding the surfaces, finding the midpoints, creating combinations of points, passing lines through them, then finding the longest lines, which I can then get the direction vector from. However that approach is wasteful, so now I’m looking into grouping surfaces by their normals first, then passing lines through their midpoints and evaluating them instead. All of a sudden you go from 15 lines to just 3, which will be a lot faster to process when you have a lot of solids. I posted about that in another thread :slight_smile: Thanks a ton for your very valuable help so far!