There is some source data, like [1 2 3 4 "a" "b" "c" "d"]
, four items as a group. I want to extract some data at specific positions, such as the first, third, and fourth from each group.
There is my code:
data: [1 2 3 4 "a" "b" "c" "d"]
output: copy []
foreach [p1 p2 p3 p4] data [ collect/into [keep p1 keep p3 keep p4] output ]
probe output ;;the output is ["a" "c" "d" 1 3 4]
But what I really want is [1 3 4 "a" "c" "d"]
. How can I keep the order?
All functions in Rebol which use the /into
option use insert
semantics. We added that option to allow incremental building without needing to make as many intermediate series, and to allow you to pick the type of target series, preallocate, and all sorts of other power user tricks. The /into
option uses insert
semantics because insert
doesn't lose as much information as append
.
Let's take your example but just use collect
:
data: [1 2 3 4 "a" "b" "c" "d"]
output: collect [
foreach [p1 p2 p3 p4] data [ keep p1 keep p3 keep p4 ]
]
probe output
That's the kind of simple code that collect
is supposed to make it easier to write. But it's a bit slow, so let's try optimizing it a bit by using /into
:
data: [1 2 3 4 "a" "b" "c" "d"]
output: copy []
foreach [p1 p2 p3 p4] data [
output: collect/into [keep p1 keep p3 keep p4] output
]
probe head output
That is the standard model for /into
code, and will make things output in the order you want. But it really doesn't have any advantages over using regular collect
, since you don't preallocate the target block. This will save on reallocations:
data: [1 2 3 4 "a" "b" "c" "d"]
output: make block! 0.75 * length? data
foreach [p1 p2 p3 p4] data [
output: collect/into [keep p1 keep p3 keep p4] output
]
probe head output
But collect
itself can be a little slow because it's not native; it's mostly a convenience function. Fortunately, we have faster native functions, which use /into
the same way:
data: [1 2 3 4 "a" "b" "c" "d"]
output: make block! 0.75 * length? data
foreach [p1 p2 p3 p4] data [ output: reduce/into [p1 p3 p4] output ]
probe head output
No non-native functions used there, this should be pretty fast.
For a reason unknown to me, collect
uses insert
internally, so it inserts data at the beginning, not append
them at the end. I hope someone can give an explanation why it's this way. Meanwhile, you can use good old repend
to do the job:
data: [1 2 3 4 "a" "b" "c" "d"]
output: copy []
forskip data 4 [repend output [data/1 data/3 data/4]]
probe output ;; [1 3 4 "a" "c" "d"]
Also, it's better to use forskip
instead of foreach
in this case, as you do not have to define variables and access just by index.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With