nforeach
[1/6] from: g:santilli:tiscalinet:it at: 22-Jul-2003 13:12
Hello all,
it often happens to me to have to iterate in parallel over two
or more series. Today I thought it was the time to solve the issue
once and for all with a specific function. :)
Note: this is rather a QAD implementation. It surely needs
improvements.
It works this way:
>> nforeach [a [1 2 3] b [4 5 6]] [print [a b]]
1 4
2 5
3 6
It also handles more complicated cases:
>> w: 'c b: [d e] nforeach [file read %./ [a b] [1 2 3 4 5 6] :w [x y z] :b [9 8 7 6
5]] [print [file a b c d e]]
desktop/ 1 2 x 9 8
edit-prefs.r 3 4 y 7 6
license.key 5 6 z 5 none
local/ none none none none none
prefs.r none none none none none
public/ none none none none none
rebol-1.2.1.exe none none none none none
rebol-link.exe none none none none none
rebol.exe none none none none none
rebol.r none none none none none
user.r none none none none none
view1210031.exe none none none none none
viewtop1200.zip none none none none none
Let me know what you think.
context [
invalid: func [arg] [throw make error! join [script invalid-arg] :arg]
ceil: func [num [number!]] [
either num > num: to integer! num [num + 1] [num]
]
set 'nforeach func [[catch] args [block!] body [block!] /local bargs words end word]
[
bargs: head clear next [body]
words: clear [ ]
end: 0
while [not tail? args] [
word: pick args 1
if not any [word? :word block? :word all [get-word? :word any [word? word: get :word
block? :word]]] [
invalid :word
]
use [series] [
set [series args] do/next next args
if not series? :series [
invalid :series
]
insert tail words word
either block? word [
repeat j length? word [
insert insert insert insert tail bargs [pick :series i - 1 *] length? word '+ j
]
end: max end ceil divide length? :series length? word
] [
insert tail bargs [pick :series i]
end: max end length? :series
]
]
]
if any [empty? words empty? bargs] [return none]
body: func words body
repeat i end bargs
]
]
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[2/6] from: greggirwin:mindspring at: 22-Jul-2003 8:33
Thanks Gabriele!
It's a good week for cool functions it seems. :)
--Gregg
[3/6] from: rotenca:telvia:it at: 22-Jul-2003 18:21
> Let me know what you think.
Good!
But you must copy bargs for recursion.
---
Ciao
Romano
[4/6] from: AJMartin:orcon at: 23-Jul-2003 18:57
Gabriele wrote:
> It works this way:
>
> >> nforeach [a [1 2 3] b [4 5 6]] [print [a b]]
I've been wanting something like this for a while. Thank you, Gabriele!
I think I might like it better like this:
>> nforeach [a b] [[1 2 3] [4 5 6]] [print [a b]]
That's because when working with a table of data (rows and columns of data)
it might be easier to write things like:
Table_Header: [a b]
Table_Rows: [
[1 4]
[2 5]
[3 6]
]
>> transpose Table_Rows
== [[1 2 3] [4 5 6]]
nforeach Table_Header transpose Table_Data [print [a b]]
Andrew J Martin
ICQ: 26227169 http://www.rebol.it/Valley/ http://Valley.150m.com/
[5/6] from: g:santilli:tiscalinet:it at: 23-Jul-2003 9:45
Hi Romano,
On Tuesday, July 22, 2003, 6:21:03 PM, you wrote:
RPT> But you must copy bargs for recursion.
You're right. There are other things it does not handle (should
have [throw] for returning from the body, and probably use
Ladislav's tfunc to avoid all of the subtle issues with these kind
of functions). I'll leave all this to the reader as an exercise.
;-)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/
[6/6] from: g:santilli:tiscalinet:it at: 23-Jul-2003 10:23
Hi Andrew,
On Wednesday, July 23, 2003, 8:57:53 AM, you wrote:
AJM> I think I might like it better like this:
>>> nforeach [a b] [[1 2 3] [4 5 6]] [print [a b]]
Ironicly, that way you'd need NFOREACH inside NFOREACH... ;-) (Of
course, if you only support the case of one word per series, it
gets simple enough. But see below, if you want to use it on
tables.)
AJM> Table_Header: [a b]
AJM> Table_Rows: [
AJM> [1 4]
AJM> [2 5]
AJM> [3 6]
AJM> ]
>>> transpose Table_Rows
AJM> == [[1 2 3] [4 5 6]]
AJM> nforeach Table_Header transpose Table_Data [print [a b]]
Hmm, I would do this as:
foreach-row: func [table-header table-rows body] [
table-header: use table-header reduce [table-header]
bind body table-header/1 ; you might want to use bind/copy
; and check for an empty table-header
foreach row table-rows [
set table-header row
do body
]
]
(untested)
Regards,
Gabriele.
--
Gabriele Santilli <[g--santilli--tiscalinet--it]> -- REBOL Programmer
Amiga Group Italia sez. L'Aquila --- SOON: http://www.rebol.it/