Multi-searches
[1/15] from: info:id-net:ch at: 20-Feb-2002 9:25
Hi all,
I want to make multi-researches on a block of strings.
The result I want is an array of index of all appereances of a name, but the
'find
word find only the first appereance and to find the second appereance I have
to find the index, then 'skip the
list to index + 1 and so on..
Is there another way to make it, because in my case, sometimes the word to
find is listed on second position of my array and sometimes
on the third? So just to make those search I need 100 rows, and it's
bugging!
Philippe
[2/15] from: joel:neely:fedex at: 20-Feb-2002 6:46
Hi, Philippe,
Philippe Oehler wrote:
> I want to make multi-researches on a block of strings.
>
> The result I want is an array of index of all appereances of a name,
> but the 'find word find only the first appereance
>
Do you mean something like this?
>> blort: [1 2 0 3 0 4 5 6 0 7]
== [1 2 0 3 0 4 5 6 0 7]
>> find-all: func [b [block!] v [any-type!] /local result] [
[ result: copy []
[ forall b [if v = b/1 [append result index? b]]
[ result
[ ]
>> find-all blort 0
== [3 5 9]
I used a block of numbers to save typing, but the principle
is the same IMHO.
HTH!
-jn-
--
; sub REBOL {}; sub head ($) {@_[0]}
REBOL []
# despam: func [e] [replace replace/all e ":" "." "#" "@"]
; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"}
print head reverse despam "moc:xedef#yleen:leoj" ;
[3/15] from: brett:codeconscious at: 21-Feb-2002 1:16
Hi Philippe,
You can use find in a loop. Save the result of the previous find so that you
do another find after the last one:
find-multiple: function [
"Searches the series and returns the positions where the value occurs."
series [series!]
value [any-type!]
][result][
result: copy []
while [all [not tail? series found? series: find/only series value]][
insert tail result index? series
series: next series
]
result
]
find-multiple ["red" "green" "blue" "red"] "red"
Regards,
Brett.
[4/15] from: info:id-net:ch at: 20-Feb-2002 14:26
Hi Joel,
Yes Joel something like that. Thanks a lot !
I tried with the FIND word but you just did with a IF test. Sometimes the
things are more, more simple as you expected 8-)
Can you explain me something ? Why (result) is a local variable and then
without the RETURN word, you typed (result) at the end of the function ?
What is the advantage of this ?
Philippe
[5/15] from: greggirwin:mindspring at: 20-Feb-2002 11:55
Hi Philippe,
<< Can you explain me something ? Why (result) is a local variable and then
without the RETURN word, you typed (result) at the end of the function ?
What is the advantage of this ? >>
REBOL functions automatically return the last thing they evaluate. It's kind
of a REBOL idiom *not* to use RETURN in that case, though I still haven't
gotten my brain to do that very often. I believe it's more efficient not to
use RETURN, so there is a "clear" argument for it as well.
--Gregg
[6/15] from: joel:neely:fedex at: 20-Feb-2002 13:32
Hi, Philippe,
Philippe Oehler wrote:
> Can you explain me something ? Why (result) is a local variable
> and then without the RETURN word, you typed (result) at the end
> of the function ?
>
The value returned from a function is the value of the last
expression evaluated within the function. A single word is,
of course, a trivial expression...
> What is the advantage of this ?
>
The only reason for using RETURN is to force non-fall-through
exit from a function. Putting it at the end of a function is
just a wasted extra word evaluation (and typing) AFAIK.
-jn-
[7/15] from: info:id-net:ch at: 20-Feb-2002 22:26
Hi Brett,
Could you explain me this line :
while [all [not tail? series found? series: find/only series value]][
I use ALL like that "all [(first test)(second test)] [consequence]" but here
? and what does the rest of the line ?
Philippe
[8/15] from: jason:cunliffe:verizon at: 20-Feb-2002 16:53
Joel Neely
<[joel--neely--fedex--com]> wrote:
> The only reason for using RETURN is to force non-fall-through
> exit from a function. Putting it at the end of a function is
> just a wasted extra word evaluation (and typing) AFAIK.
Joel
That's interesting. Could you expand a little please..
What do you mean by "non-fall-through exit" ?
thanks
./Jason
[9/15] from: al:bri:xtra at: 21-Feb-2002 15:15
Philippe wrote:
> Could you explain me this line :
> while [all [not tail? series found? series: find/only series value]][
Sometimes it helps to see it like:
while [
all [
not tail? series
found? series: find/only series value
]
][
; and so on.
Does that help make it clearer?
Andrew Martin
ICQ: 26227169 http://valley.150m.com/
[10/15] from: joel:neely:fedex at: 20-Feb-2002 20:31
Hi, Jason,
Jason Cunliffe wrote:
> That's interesting. Could you expand a little please..
> What do you mean by "non-fall-through exit" ?
>
A "fall-through" exit is one that "falls" out of the end of the
function. A non-fall-through exit terminates the function
evaluation prior to reaching the end of the normal sequential
flow. RETURN essentially acts as "go to the out door".
Here's a strict one-way-out function to compute the real roots
of a quadratic equation.
If the discriminant is... ...there are _ real roots.
------------------------- --------------------------
negative no
zero two equal
positive two distinct
8<------------------------------------------------------------
quadform1: func [a [number!] b [number!] c [number!] /local d] [
d: b * b - (4.0 * a * c)
either d < 0 [
[]
][
a: 1.0 / 2.0 / a
b: - b
either d = 0 [
reduce [b * a]
][
d: square-root d
reduce [b + d * a b - d * a]
]
]
]
8<------------------------------------------------------------
Notice that this "purist" version uses nested conditions to
evaluate only the appropriate expressions. In contrast:
8<------------------------------------------------------------
quadform2: func [a [number!] b [number!] c [number!] /local d] [
d: b * b - (4.0 * a * c)
if d < 0 [return []]
a: 1.0 / 2.0 / a
b: - b
if d = 0 [return reduce [b * a]]
d: square-root d
reduce [b + d * a b - d * a]
]
8<------------------------------------------------------------
the above version uses "early exits" via RETURN to bail out as
soon as the result is determined. YMMV but some folks think
that the second version is easier to read because of the
absence of nesting.
Of course these two are equivalent mod a trivial syntactic
rewrite. Sometimes early exits make a significant difference
in structure or performance. Consider a function that tests
whether all numbers in a block are even:
8<------------------------------------------------------------
alleven1: func [blk [block!] /local evensofar] [
evensofar: true
foreach nbr blk [
evensofar: evensofar and even? nbr
]
evensofar
]
8<------------------------------------------------------------
That one is certainly correct, but may work more than necessary
(since FALSE is a zero for AND). It can be written (at a cost
of performance) to make explicit tests of both the state of
the block and the state of the accumulator variable:
8<------------------------------------------------------------
alleven2: func [blk [block!] /local evensofar] [
evensofar: true
while [all [not empty? blk evensofar]] [
evensofar: even? first blk
blk: next blk
]
evensofar
]
8<------------------------------------------------------------
...but that's just clunky-looking. Both of those functions
used fall-through exits, because they were structured to flow
all the way to the end. If we take off our purist hats and
take advantage of RETURN, we can write this as:
8<------------------------------------------------------------
alleven3: func [blk [block!]] [
foreach nbr blk [
if odd? nbr [return false]
]
true
]
8<------------------------------------------------------------
The RETURN is necessary *inside* the loop to force early
departure from the function. At the end, we only need to
provide the (trivial) expression for the result.
HTH!
-jn-
--
; sub REBOL {}; sub head ($) {@_[0]}
REBOL []
# despam: func [e] [replace replace/all e ":" "." "#" "@"]
; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"}
print head reverse despam "moc:xedef#yleen:leoj" ;
[11/15] from: chalz:earthlink at: 21-Feb-2002 0:01
I'm sure someone else has gotten to this already (I only get to my email
about once every 24hrs), but in case someone else hasn't mentioned this,
there's always the good old method of (I know this isn't all totally proper
REBOL, or good code):
test: x
list: [a b c d ...]
idxs: []
i: 0
foreach val list [
i: i + 1
if val = test [join idxs i]
]
return idxs
I'm sure there are far more elegant methods in REBOL, but, I was 'trained'
in C and C-style systems.
[12/15] from: carl:cybercraft at: 21-Feb-2002 19:56
On 21-Feb-02, Philippe Oehler wrote:
> Hi Joel,
> Yes Joel something like that. Thanks a lot ! I tried with the FIND
> word but you just did with a IF test. Sometimes the things are more,
> more simple as you expected 8-)
Hi Philippe,
Joel's answered you fine, but your question suggested another possible
approach to me if (though only if) you were looking for series within
a block. What the following does is to put what you're looking for
in the block that's returned instead of the index numbers. It's
easier to show you than explain I think, so...
find-series: func [blk [block!] ser [series!] /local result][
result: copy []
forall blk [
if blk/1 = ser [append result blk/1]
]
result
]
>> a: ["fe" "fi" "fo" "fe" "fi" "fo"]
== ["fe" "fi" "fo" "fe" "fi" "fo"]
>> b: find-series a "fo"
== ["fo" "fo"]
The two "fo"s in 'b there are the same strings that appear in 'a, so
that allows us to do the following kind of stuff...
>> append b/1 "1"
== "fo1"
>> a
== ["fe" "fi" "fo1" "fe" "fi" "fo"]
>> b
== ["fo1" "fo"]
and...
>> append b/2 "2"
== "fo2"
>> a
== ["fe" "fi" "fo1" "fe" "fi" "fo2"]
>> b
== ["fo1" "fo2"]
Hope that's of interest even if it's not of specific use to your
current project.
> Can you explain me something ? Why (result) is a local variable and
> then without the RETURN word, you typed (result) at the end of the
<<quoted lines omitted: 21>>
>> HTH!
>> -jn-
--
Carl Read
[13/15] from: brett:codeconscious at: 21-Feb-2002 20:44
Hi Philippe,
> Could you explain me this line :
> while [all [not tail? series found? series: find/only series value]][
Andrew's formatting maybe have explained it for you, but if not, some more
detail is below.
> I use ALL like that "all [(first test)(second test)] [consequence]" but
here
> ? and what does the rest of the line ?
First off, in case it helps, a quick correction to your example. ALL takes
only one parameter, a block. The "[consequence]" part of your example
is not used by ALL at all. Probably your example is part of an IF
statement like this:
IF condition [consequence]
E.g:
>> if true [now]
== 21-Feb-2002/20:00:37+11:00
>> if all [1 2] [3]
== 3
Now on to ALL.
ALL evalutes a block of expressions. If during that evaluation one of
those expressions results in none! then ALL returns none!. If all the
expressions are not none! then ALL returns the result of the last
expression. Examples:
>> all [1 2 3 4 5]
== 5
>> all [1 2 now]
== 21-Feb-2002/19:50:44+11:00
>> all [1 2 none 4 5]
== none
Back to my line. I intended this part of the line:
[
not tail? series
found? series: find/only series value
]
to have two results.
The first result is to make sure that there is something left to process.
The second result is true only if the value is found in the the remaining
part of the series.
If either of these results in none! ALL will return none! and the while
loop will stop. When both are true it means that I have a value to
process.
The second result may look odd to you. I didn't really need to use
found?
but I did to emphasize where the second result was going
to come from. You can as easily delete "found?" from the line - the
condition will still work.
find/only series value
finds the value in the series. If the value is
found then the result of this is the same series but it's index
(position) modified to where the value occurred. I capture this
result into the same variable "series". If the value was not found
you get a none!
So the series index gets moved up if a value is found. It gets
moved to the value.
The body part of the while loop runs for each value that is
found. It adds the value to the result and then it moves
the series index again to prevent an infinite loop.
I hope that is helpful!
Regards,
Brett.
[14/15] from: joel:neely:fedex at: 21-Feb-2002 5:18
Hi, again, all,
Minor quibble...
Brett Handley wrote:
> ALL evalutes a block of expressions. If during that evaluation
> one of those expressions results in none!
>
... or FALSE ...
> then ALL returns none!. If all the expressions are not none!
> then ALL returns the result of the last expression...
... so that it behaves somewhat like a generalized AND.
-jn-
--
; sub REBOL {}; sub head ($) {@_[0]}
REBOL []
# despam: func [e] [replace replace/all e ":" "." "#" "@"]
; sub despam {my ($e) = @_; $e =~ tr/:#/.@/; return "\n$e"}
print head reverse despam "moc:xedef#yleen:leoj" ;
[15/15] from: jason:cunliffe:verizon at: 23-Feb-2002 12:05
Joel Neely
<[joel--neely--fedex--com]> wrote:
> > That's interesting. Could you expand a little please..
> > What do you mean by "non-fall-through exit" ?
>
> A "fall-through" exit is one that "falls" out of the end of the
> function. A non-fall-through exit terminates the function
> evaluation prior to reaching the end of the normal sequential
> flow. RETURN essentially acts as "go to the out door".
etc..snip another great answer from Joel...
Joel
thanks again for a wonderful lesson!
./Jason
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted