Jump to content
View in the app

A better way to browse. Learn more.

FMForums.com

A full-screen app on your home screen with push notifications, badges and more.

To install this app on iOS and iPadOS
  1. Tap the Share icon in Safari
  2. Scroll the menu and tap Add to Home Screen.
  3. Tap Add in the top-right corner.
To install this app on Android
  1. Tap the 3-dot menu (⋮) in the top-right corner of the browser.
  2. Tap Add to Home screen or Install app.
  3. Confirm by tapping Install.

RFC - Repeat Function Idea

Featured Replies

  • Author

Sure, but ForEach with Range/Counter gives you the choice to have either, or both:

Let( myList = "apple¶bear¶cat";

  ForEach( [idx = Range(1,ValueCount(myList)); v = myList]; idx & ". " & v & ¶) )

resulting in:

  1. apple

  2. bear

  3. cat

Passing *only* the index is inefficient, as a good percentage of the time that index would be passed back to a GetValue() call, which is just waste, since we could have had the value itself for cheap/free rather than having to look it up again.

ForEach can *also* process a string:

  ForEach( v = Range(1,Length(myString)); Middle(myString,v,1) )

So I'm not seeing the extra value of a counter-only ForEach.

---

An issue I see with your example to avoid Range is that it would be giving back the wrong index if the listOfValues had duplicates.

  • Author

Regarding ValuePosition()B)

Allowing searchValue to have multiple values (actually a block of values) would be a nice feature - although I don't see much use of it. That is, I'd rather have one without it sooner than with it later.

Well, if the function exists, it has to do *something*. The choices I see are:

   1) Return an error.

   2) Grab the first value from the list, and only use it.

   3) Search for all the values supplied.

If you don't care, then that's fine, but a complete design for a function needs to at least consider these things.

Passing *only* the index is inefficient, as a good percentage of the time that index would be passed back to a GetValue() call

That is true, if you're mostly going to process value lists. I realize that's where your idea originally started, but I am thinking of something more general, and much more versatile. The way you have it, it's designed specifically to process value lists, but you can also make it general by adding a counter. To me, it seems more elegant having a general function as the basis, and adapting it to process value lists by using GetValue() - just as you could use Middle() to process a string character-by-character, or GetNthRecord() to process a found/related set. This way, the average amount of added processing is evenly distributed among the types of usage.

a complete design for a function needs to at least consider these things

Hm. It's not that I don't care, but it's hard to come up with a practical example where I would need this. It also depends on the other issue we're discussing. If ForEach() is going to be designed to deal first and foremost with value lists, then value lists are the thing. In such case, I think I would want ValuePosition() to return a separate index value for each searched value - also as a list. Otherwise I would go with #3 - search for the entire block.

FWIW I talked with Agnes early on during the development of her CF. It's an interesting concept but eliminating recursion doesn't really accomplish anything. I have a much simpler version, that does use recursion. It has recursion limits but the limit is higher and performance is essentially identical. See http://www.briandunning.com/cf/751

I have been following this discussion with interest. Much is over my head, but am learning. Checked out your custom function. Also, went to your website, your homepage but cannot enter the site, ie. go to any pages. ?

  • Author

I do think value processing is much more common than word / letter processing. Maybe its just the way I think about things but it seems like most of the questions that need a CF (for looping) on this forum are about value processing.

I was going to mention, part of the reason I think "Range" is a better name that "Counter" is that the function is useful in other contexts besides the loop. It can preserve the type of the argument up until the list needs to be constructed, so:

  Let( d = Date(12,7,2007); Range( d; d+(4*7)-1; 7 ))

results in: "12/7/2007¶12/14/2007¶12/21/2007¶12/28/2007¶"

which could be used to break a time range into 15 minute increments also, and that kind of thing. I think the name "Counter" implies its only useful in conjunction with ForEach, which I don't see as being the case at all.

Dear Bruce,

Agnès sent me this recursive version ways before you published yours and advertised it as being a creation of yours, without even mentionning her name in the comments...

Unfortunately, it is still much slower than CustomList, and limited to 10,000 items. More, I'm not sure to understand what's so simple about it B) all 3 parameters are exactly the same as CustomList's.

Give back to Ceasar...

Edited by Guest

I absolutely agree with you Shawn. Range() is much more powerful than Counter(), and much more explicit.

As far as word by word processing is concerned, I have to say that I developed FilterWordsByTest() before FilterValuesByTest() because I needed it on some project, but I haven't used it much since that, unlike FilterValuesByTest, which I have used at least on a daily basis until CustomList was released.

So again, you're right B)

[sorry to take it so personnally, but I cannot muzzle myself with what Bruce said. It's surely off-topic, but FWIW]

FWIW I talked with Agnes early on during the development of her CF. It's an interesting concept but eliminating recursion doesn't really accomplish anything. I have a much simpler version, that does use recursion. It has recursion limits but the limit is higher and performance is essentially identical.

We don't "talked with Agnes early on during the development of her CF" !! isn't not the true...

I started to write CustomList() at the beginning of April, with the assistance of Ugo and Fabrice,

[color:blue]I published CustomList in [color:red]April B) http://www.fmsource.com/forum/index.php?s=&showtopic=33993&view=findpost&p=139817

And I show CustomListRec, Recursive version of CustomList In [color:red]June http://www.fmsource.com/forum/index.php?s=&showtopic=33993&view=findpost&p=139872 I published the recursive version to show that the NotRecursive version was much faster

You send me a mail in [color:red]August, when I published CustomList In the BrianDunning's site, to say to me that one needed a getAsNumber for start and End

and we discussed the recursivity and I sent to you a mail with the Recursive version to show you, by you specifying that it was slower and that I did not want especially to publish it on the BrianDunnig's Site !

I believe the NotRecursive version is much more interessante and more rapid than recursive version

I am can be impulsive but I do not understand that anyone take the work of the others without at least specifying it, and while letting to believe that it is its work, its idea.

and even if you changed my recursive version a little, I do not understand that you published it without to at least to have asked it me.

IMHO , I think is not a copy but a "plagiat" to my cf and my work,

and I doubt :

and performance is essentially identical

.... then, Just for fun.... B)

Test on MacOS_10.4 | TowerG5 | PowerPC G4 | Intel with FM 8.5 - The same calcul for the recursive and the NotRecursive, 2000 records. simple calcul, SetField, not with loop

CustomList ( 1; 2000 ; "[n] & "." & GetNthRecord (TableA::Name ; [n] )" )

G5 -> 1 sec | PC : 3 sec | Intel Immediate Result

ListFunction ( 1; 2000 ; "[n] & "." & GetNthRecord (TableA::Name ; [n] )" )

G5 -> 9 sec | PC : 21 sec | Intel 3 sec

4000 values just with Intel CL 2 seconds, LF 8 seconds

it's a difference no ?

May I add that the Non recursive version can be used by FM8+ users without any need for an Advanced version ?

Thanks,

Agnès

[off Topic : sorry]

Edited by Guest
........

The thing that bothers me about the name "Range()" is that range is the input to the function. A function, I think, should be named by what it does or by what it outputs. This function takes a range and expands it into a list by enumerating - roughly the opposite of this: http://www.briandunning.com/cf/734

I do think value processing is much more common than word / letter processing. Maybe its just the way I think about things but it seems like most of the questions that need a CF (for looping) on this forum are about value processing.

Well, everybody has their own perspective. A very rough count of my CF folder shows list processing accounts for less than 15%. Text is about 40%. I have about 120 files there, and I'd say at least half of those were produced following a question on the forums.

[Edit First Post]

Edited by Guest
..... to muzzle myself........ ;)

Hi,

Staying on the subject, I'd agree with Mike the name "Range" may be too tied to the output, but then "Count" is too close to a counter/loop thing as well.

What Shawn decribes with

"Let( d = Date(12,7,2007); Range( d; d+(4*7)-1; 7 ))"

may be achieved without any extra new function with a simple repeating field. This would be sufficient to rename my calcField, eventually the Custom Function I'd be using, but it still is a ******* repeating field calculation, whatever the function I used. Should I be naming it "Repeat ()" ?

This is the basic problem when functions may be used for so many things at one time. Thought, thinking it loud, I would think that this kind of function may be one of the first "Set" prefixed function.

Edited by Guest
******** = ****

Swear in French or Italian, and see if you get the ********

Swear in French or Italian, and see if you get the ********

rofl B)

Perhaps it's worth noting that a list of values is ALWAYS going to be Text. So to me, it doesn't matter so much if the output is "12/7/2007¶12/14/2007¶12/21/2007¶12/28/2007¶" or "733017¶733024¶733031¶733038¶". Actually, I can think of situations where I'd prefer the latter.

Actually Numbers() could then do the trick as well B)

And Lee, I'm trying not to be rude...that's all B)

No, "Numbers" is Apple's spreadsheet. B) But Numerator() would work for me.

Lee, I'm trying not to be rude...that's all B)

And I was hoping to learn a few new words. :giggle:

Dam

Lee

  • Author

Staying on the subject, I'd agree with Mike the name "Range" may be too tied to the output, but then "Count" is too close to a counter/loop thing as well.

It's not that I love the name Range(), but I think its better than Counter(), which makes it seem like its only for use when iterating.

By the way, *if* this function were accepted into the product, it's the human interface designers who come up with the final name - not programmers, and especially not those who don't work there anymore, so I doubt my suggestion to them will have any effect. B)

I stopped over in Santa Clara today and made my pitch, btw. They seemed interested and will consider it, with no promises, of course.

I can't recall but I'm fairly sure Michael made a suggestion somewhere of "Enumerate" - I would think this would be the most logical word, and its not like FM is afraid of long words e.g. Substitute, PatternCount, MiddleValues ...

Enumerate(low,high)

It also defines a lot better than range:

- to specify one after another

- to mention separately as if in counting; name one by one; specify, as in a list.

Better yet, you could call the function: EnumerateRange(low,high).

Range, at least to me, seems a little vague compared to most of the other FM functions.

Edited by Guest

  • Author

Perhaps it's worth noting that a list of values is ALWAYS going to be Text.

So to me, it doesn't matter so much if the output is

    "12/7/2007¶12/14/2007¶12/21/2007¶12/28/2007¶"

or

    "733017¶733024¶733031¶733038¶".

Actually, I can think of situations where I'd prefer the latter.

The way I implemented the prototype code, it always attempts to propagate the type of the first argument, so:

  Let( d = Date(12,7,2007); Range( GetAsNumber(d); d+(4*7)-1; 7 ))

would produce your preferred output.

For what its worth, this basic recursive CF demonstrates how I would think the Range portion of this at least would work...

EnumerateRange( low ; high ; factor )B)

Case( low <= high  ; low & ¶ & EnumerateRange( low + factor ; high ; factor ) )

I don't think we should lock ourselves into any hardcoded interpretations of variables - the fm engine already knows how to add to different data types, and we have the ability to use those types directly as we need them to get whatever output we desire.

EnumerateRange(0 ; 1000 ; 5)

"0¶5¶10¶...¶995¶1000"

Type cast it...

EnumerateRange( GetAsDate("12/1/07") ; GetAsDate("12/12/07") ; 7)

"12/01/2007¶19/01/2007¶26/01/2007¶...¶7/12/2007"

EnumerateRange( GetAsNumber(GetAsDate("12/1/07")) ; GetAsNumber(GetAsDate("12/12/07")) ; 7)

"732688¶732695¶732702¶...¶733017"

Case( low <= high

I don't see why it shouldn't go in the negative direction too, e.g. Enumerate ( 10 ; 0 ; -2 ) returns "10¶8¶6¶4¶2¶0", and Enumerate ( 10 ; 0 ; 2 ) returns "?", I guess.

---

As long as I am nitpicking, "factor" is something you multiply by. I'd pick "increment" or - to keep it the same as the SerialIncrement() function - "incrementBy".

Yeh the factor thought crossed my mind. The negative thought never crossed my mind but its definitley a good point.

EnumerateRange( start ; end ; increment )B)

If( Case( increment > 0 ; start <= end ; increment < 0 ; end <= start ) ; start & ¶ & EnumerateRange( start + increment ; end ; increment ) )

Lol, or change increment to dincriment... lol get it? Sigh... that has got to be the lamest thing i've ever said, oh well.

.. Ignoring the question mark which would be returned for any invalid submissions.

Edited by Guest

  • 2 weeks later...

Dear Bruce,

Agnès sent me this recursive version ways before you published yours and advertised it as being a creation of yours, without even mentionning her name in the comments...

Unfortunately, it is still much slower than CustomList, and limited to 10,000 items. More, I'm not sure to understand what's so simple about it B) all 3 parameters are exactly the same as CustomList's.

Give back to Ceasar...

1. If Agnes sent it to you without my comments - why did she do that? See the only place I've publicly posted it, on Brian Dunning's list, where the very first line mentions Agnes.

2. During my tests while communicating with Agnes on this subject I demonstrated that the claimed speed advantage of her function did not exist.

3. Because of tail recursion, the recursion limit is 50K, not 10K.

4. My CF is about 8 lines of actual function. Leaving aside other issues, it is far easier to understand and modify for your own purposes.

5. Do you complain to people who submit alternate quicksort functions or other custom function variations?

Edited by Guest

Create an account or sign in to comment

Important Information

By using this site, you agree to our Terms of Use.

Configure browser push notifications

Chrome (Android)
  1. Tap the lock icon next to the address bar.
  2. Tap Permissions → Notifications.
  3. Adjust your preference.
Chrome (Desktop)
  1. Click the padlock icon in the address bar.
  2. Select Site settings.
  3. Find Notifications and adjust your preference.