Patterns and Practices: Iterating Collections Part Deux – Well hello there, For Each
In a previous post, I reviewed how to solve a common authoring need of iterating a collection, using both the While Loop and Execute Member Rule Set constructs. I highlighted the benefits of using the Execute Member Rule Set over the While Loop.
With version 5.0.19, I’m very excited to introduce a new rule construct for this need: the For Each loop.
Please review my previous post to refresh your memory on the specific authoring example I presented. To introduce For Each, I thought it would make perfect sense to solve that same problem using this new rule construct.
So, I started with my While Loop Rule Application. I used this example rather than the Execute Member Rule Set as the starting point because the For Each rule, like the While Loop, will also be written at the parent level (the level which contains the collection to iterate).
I loaded up that example into the new version and created a new rule set called “MyForEachLoop.” I then copied over the While Loop contents and starting making relevant updates.
You can see below the side by side comparison of the end product.
I tested these rule sets and they produce the same results. However, as you can see by the picture alone, the For Each loop is more efficient and less complex to author.
In addition to being able to cut out a few pieces completely (e.g. counter index nonsense), I found another efficiency. When I wanted to apply a filter to my While loop, I realized that I initially made a mistake and only impacted the number of times I would iterate through that full collection based on the filter count. To get the results I wanted, I needed to add my filter to an If condition within the loop itself.
While Loop Filter (within loop)
However, with the For Each loop, I could easily apply a filter at the loop level. In this case, InRule won’t iterate through the members that don’t match the filter.
NOTE: The filter is in both the context of the parent and the context of the collection member. Therefore, you do not need to use the member variable name.field name syntax here; you can refer to the field on the member directly.
For Each Loop Filter (at the loop level)
Here’s the summary of what I learned:
Benefits of For Each over While Loop:
- No need to declare and initialize a counter / index
- No need to declare and initialize a variable that is the member of the collection you’re iterating (based on the current counter index). NOTE: If you didn’t do this with a While Loop, then every time you reference that collection member, you have to refer to it by index.
- No need to increase the counter at the end of the loop
- You can apply a filter to the loop. Members that don’t meet the criteria will not be iterated, making the loop more efficient.
Now, you may be asking yourself, what about For Each vs. Execute Member Rule Set? Well, I did find a few benefits of For Each over that rule construct as well.
Benefits of For Each over Execute Member Rule Set:
- Can write the rule in the context of the parent that owns the collection. This is probably more natural.
- Do not need to create a rule set to hold all of the loop logic (which can end up creating lots of rule sets solely for the purpose of iterating collections)
For Each can really come through in a pinch when you need to perform a quick operation across a collection that doesn’t necessarily warrant breaking out into its own rule set. Ultimately, the litmus test to apply for when to use For Each vs Execute Member Rule Set comes down to the scope and relevance of the business logic contained within the iteration. If there is significant business logic being performed on each collection member, then these rules are generally better served in a rule set in the child entity context (Execute Member Rule Set), where the rules can be expressed more clearly outside of the iteration. On the other hand, if you are simply performing some basic field initialization or rudimentary calculations across the members, then For Each is probably more appropriate.
If your scenario is in a gray area, it could come down to personal preference. Developers are likely more familiar with the For Each construct, as it behaves very similarly to how it would in code, but a business analyst may prefer Execute Member Rule Set since they are not biased by the familiarity of For Each.
As with anything, there are many different ways to solve the same problem. Now with the latest version of InRule, there is yet another tool in the proverbial toolbox!