Hi folks,
It's the first Question of the Week on the new community, and it's all very exciting. If you want to see more of this type of content, don't forget to click the Follow button in the top right of the screen.
Today we're looking at a common issue: whether a loop is necessary in a workspace.
Question of the Week
In this question, @hlouie asks:
Q) rI'm] Trying to find a way of creating multiple records from a range by interval some way of looping, adding 100, create new, looping until max.
A) Herman mentions "looping", but the thing is, that's not necessary in this case. Many users who are used to scripting and algorithms often look to a loop as the first solution for a problem, and I can see why (I do it too). But - as we'll see - that's not always necessary...
The Scenario
So, the scenario is that we have a single feature, with an ID number (here 3,700). We need to create a number of copies of this feature, incrementing the ID by a set number (here 100) each time.
So: 3,700; 3,800; 3,900; 4,000 and so on.
The wrinkle is that we don't know how many to create; we only know a maximum value for this ID (here not specified, but I picked 4,050)
Logic suggests we loop the feature, each iteration cloning it to a new feature and assigning a new ID. The loop exits on the condition that ID > Maximum ID
But logic isn't always correct, because FME can sometimes work better with - dare I say it - alternative logic!
A Cloner-Based Solution
Here's my workspace (adapted using suggestions from @debbiatsafe):
The Creator creates the first feature. I parameterized the the initial ID number, the maximum ID number, and the interval, and the ParameterFetcher retrieves these values.
The Cloner then creates X copies. But how do we know X? Well, I calculate it using:
(@int((@Value(MaxNumber)-@Value(StartNumber))/@Value(IntervalNumber)))+1
Basically, I find the range of numbers (max - starting ID) and divide by the interval. This gives me the number of required features. I round down to an integer and then add one, because the Cloner doesn't include the incoming feature in its cloned output.
The ExpressionEvaluator sets the new ID for each feature using:
@Value(StartNumber)+(@Value(_copynum)*@Value(IntervalNumber))
The _copynum attribute is a copy number provided by the Cloner. So multiply the copy number by the interval, adding the starting ID.
Now I have this:
Four features, numbered 3,700; 3,800; 3,900; and 4,000.
But why is it important to use this method, and not loops?
Why Not Looping?
Another question this week, this one from @jkr_da, had a similar need:
Q) I got my Looping Transformers working but it feels wrong to do it the way I solve it now. How would others solve my problem?
That's a fantastic question. The thing is, FME is not naturally a looping tool. An FME workspace just doesn't flow the same way as a script would, and so looping isn't such a high priority. For years I tried to find a good looping example to add to our training, and for years I failed. There are just so few occasions that you would need it.
It's not bad to use looping, but I think that a non-looping solution is quicker and easier to create, and performs better. You just need to get your head around the central concept, which I think is best described as this:
You don't need to create a loop, because each transformer - by processing features separately - is its own form of loop.
Think of the ExpressionEvaluator in my workspace above. It processes each feature separately without being told to. You don't need to set up a loop to say:
for feature in featureList:
getFeature()
newID = @Value(StartNumber)+(@Value(_copynum)*@Value(IntervalNumber))
until end of featureList
The ExpressionEvaluator just does that itself. Looping is built in. So you don't, usually, have to add your own loops into a workspace.
Incidentally, @jkr_da's question is still unanswered, so if you can see how to avoid a loop in their scenario, then do let them know.
Other Notable Questions
Here are some other notable questions I saw this week:
- In this question, @michiedem asks why separate counters aren't starting from the required number.
- As noted by @ebygomm , the issue is that Counters have a scope. They can be local (where they all have their own count sequence) or global (where they share a count sequence). Here a local count sequence is all that was needed.
- @chloesun wanted to know if there is a Slack channel for users and staff to communicate.
- Not usually. We've only done that a couple of times, when we're collaborating with users on a specific project. Any FME-related questions can be asked in these forums, and we'll hopefully set up a Group in future for social and fun conversations.
- I did notice that there's a Reddit sub for FME. While I don't want to divert users from this community, it was created by users, so it must fill some need.
- Is it possible to replace negative raster values with abs() positive ones, asks @oliver.morris
- Yes, and @ebygomm answers again, this time with the RasterExpressionEvaluator, which indeed was created to allow cell-based calculations in raster data.
- @lazarlubomir wanted to know how to test for combinations of characters.
- Thankfully, rather than regex, @davtorgh was able to suggest the InlineQuerier, a solution I like very much.