December 1, 200718 yr 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.
December 1, 200718 yr Author Regarding ValuePosition() 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.
December 1, 200718 yr 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.
December 1, 200718 yr 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.
December 3, 200718 yr 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
December 3, 200718 yr 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. ?
December 3, 200718 yr 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.
December 3, 200718 yr 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 all 3 parameters are exactly the same as CustomList's. Give back to Ceasar... Edited December 3, 200718 yr by Guest
December 3, 200718 yr 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)
December 3, 200718 yr [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 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.... 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 December 4, 200718 yr by Guest ........
December 3, 200718 yr 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.
December 3, 200718 yr [Edit First Post] Edited December 3, 200718 yr by Guest ..... to muzzle myself........ ;)
December 3, 200718 yr 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 December 3, 200718 yr by Guest ******** = ****
December 3, 200718 yr 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.
December 3, 200718 yr Actually Numbers() could then do the trick as well And Lee, I'm trying not to be rude...that's all B)
December 4, 200718 yr Lee, I'm trying not to be rude...that's all And I was hoping to learn a few new words. Dam Lee
December 4, 200718 yr 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. I stopped over in Santa Clara today and made my pitch, btw. They seemed interested and will consider it, with no promises, of course.
December 4, 200718 yr 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 December 4, 200718 yr by Guest
December 6, 200718 yr 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.
December 6, 200718 yr 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 ) 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"
December 6, 200718 yr 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".
December 6, 200718 yr Yeh the factor thought crossed my mind. The negative thought never crossed my mind but its definitley a good point. EnumerateRange( start ; end ; increment ) 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 December 6, 200718 yr by Guest
December 16, 200718 yr 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 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 December 16, 200718 yr by Guest
Create an account or sign in to comment