Most elegant way to extract block by skipping every 2 element - rebol

Let's say I have
block: [a 1 b 2 c 3]
I want
[1 2 3]
Something like this is clunky and it doesn't work because I use word type (I'd like to have it word with word not string):
block: [a 1 b 2 c 3]
block2: []
counter: -1
foreach 'element block [
counter: negate counter
if counter append block2 element
]

The EXTRACT function should fit the bill here:
>> extract/index [a 1 b 2 c 3] 2 2
== [1 2 3]
It's fairly versatile for this type of thing.
>> help extract
USAGE:
EXTRACT series width
DESCRIPTION:
Extracts a value from a series at regular intervals.
EXTRACT is a function! value.
ARGUMENTS:
series [series!]
width [integer!] "Size of each entry (the skip)".
REFINEMENTS:
/index => Extract from an offset position.
pos [integer!] "The position".
/into => Provide an output series instead of creating a new one.
output [series!] "Output series".

Related

Value of local variables in a function seems not be released post function calling in Red/Rebol language

I construct a function named find-all to find all indexes of a given item in a series by "recursive".
The first calling of find-all gives the right output. However from the second calling, all outputs are appended together.
find-all: function [series found][
result: []
either any [empty? series none? s-found: find series found]
[result]
[append result index? s-found
find-all next s-found found]
]
;; test:
probe find-all "abcbd" "b" ;; output [2 4] as expected
probe find-all [1 2 3 2 1] 2 ;; output [2 4 2 4]
Since variables inside a function created with function are local, why does the value of variable result is still there during later funtion callings, which cause the result of the sencond calling of find-all does not begin with []?
And what is the correct recursive way to achieve this funciton?
The answer is evident if you inspect find-all after making these two calls:
>> ?? find-all
find-all: func [series found /local result s-found][
result: [2 4 2 4]
either any [empty? series none? s-found: find series found]
[result]
[append result index? s-found
find-all next s-found found
]
]
result is an indirect value, and its data buffer is stored on a heap. The data gets preserved between the calls and accumulated, because you do not re-create it with copy — result being local to function's context is unrelated to that.
Thanks to #9214's help, especially the description about indirect value. I give a solution like this:
find-all: function [series found][
either any [empty? series none? s-found: find series found]
[[]]
[append
reduce [index? s-found]
find-all next s-found found
]
]
;; test:
probe find-all "abcbd" "b" ;; output [2 4] as expected
probe find-all [1 2 3 2 1] 2 ;; output [2 4] as expected

How to modify each element of a block by "foreach" in red/rebol

I want to modify each element of a block by foreach. I tried like this but failed:
>> a: [3 4 5 6]
== [3 4 5 6]
>> foreach i a [i + 1]
== 7
>> a
== [3 4 5 6] ;; block a is not changed. What I want is [4 5 6 7]
Is there a better way to achieve it?
Changes that you made to values do not persist in a block itself. This ties back to your question about call-by-value parameter passing in Rebol and Red: you modify a copy on the stack (passed down to + along with 1), not the actual value slot that sits inside block a.
To achieve what you want, you need to increment integers in-place, without pushing them on the stack. One way to do so is by using forall.
>> block: [1 2 3]
== [1 2 3]
>> also block forall block [block/1: block/1 + 1]
== [2 3 4]
What forall does is setting a word to a series and then incrementally bumping its index:
>> forall block [probe block]
[1 2 3]
[2 3]
[3]
Since it doesn't extract the actual values, you can access them using path notation, and then modify them in place. block/1 always pick the first value on each iteration.
As usual, no reply with your foreach.
a: [2 3 4 5]
b: copy []
foreach i a [append b i + 1]
and if you wish you can set a to b now
a: b
The problem with doing this in one step is that you do not have an index you can use here (despite the suggestive letter i, but that is representing the content of each item inside the block).
So now you can choose your favourite solution.
>> help forall
USAGE:
FORALL 'word body
DESCRIPTION:
Evaluates body for all values in a series.
FORALL is a native! value.
ARGUMENTS:
'word [word!] "Word referring to series to iterate over."
body [block!]
use forall
> a: [3 4 5 6]
== [3 4 5 6]
>> forall a [a/1: a/1 + 1]
== 7
>> probe a
[4 5 6 7]
== [4 5 6 7]

Mozart/Oz: how to make record with Record.make

I am trying to create a record from list using Record.make:
declare
L=[z [a b] [1 2]]
{Record.make L.1 L.2 0}
but getting an error:
Expected type: feature
At argument: 1
How to make a second argument L.2 to be A 'feature' type? I assume L.2 is a [a b] list.
Record.make creates a record with fresh (i.e. unbound) values. For example:
R = {Record.make label [a b]}
Maybe you want List.toRecord instead:
R = {List.toRecord label [a#1 b#2]}

Array Numpy Side Effect

I found a strange effect when permuting array with numpy:
def permute(yy, kmax) :
kmax=5
kk= np.random.uniform(1,kmax)
nn= int(np.floor(len(yy)/kk))
yy3= np.zeros_like(yy );
np.copyto(yy3,yy)
for ii in range(0, nn):
ax= kk*ii-kk*nn
aux= yy[ax]
aux2= yy[kk*ii]
yy3[ax] = aux
yy3[kk*ii] = aux2
return yy3
and
yy= np.random.normal(0,1,50000)
yy1= permute(yy,2)
( np.var(yy)- np.var(yy1) )
( np.mean(yy)- np.mean(yy1) )
Result is not zero !!!
Do you think this comes from reference assignment in the array ?
I ran your function with np.arange(10) and got
1752:~/mypy$ python stack35004877.py
0.0
0.0
[0 1 2 3 4 5 6 7 8 9] # yy
[0 1 2 3 4 5 6 7 8 9] # yy1
And repeated it with the large random array, with the same 0s for the statistics.
Note that your code did not permute the input
Maybe it will be clearer if I clean it up:
def permute(yy, kmax=5) :
kk= np.random.randint(1,kmax) # int rather than float
nn= int(np.floor(len(yy)/kk))
print(nn,kk)
yy3= yy.copy()
for ii in range(0, nn):
ind1 = kk*ii
ind2 = ind1-kk*nn
yy3[ind2] = yy[ind2]
yy3[ind1] = yy[ind1]
return yy3
You aren't moving anything; and with kmax=2 you just copy every thing from yy to yy3 - something you already did outside the loop. With kmax=5 you don't copy everything in the loop - but the initial copy hides that.
With random.uniform(), kk is a float, and the indexes are also floats. That's not desirable, but apparently not a problem.
But even if I switch the indices:
yy3[ind2] = yy[ind1]
yy3[ind1] = yy[ind2]
I don't permute anything, because ind2 a negative value, that maps on to the same element as ind1. yy[-1] is the last item of yy.
[(0, -10), (1, -9), (2, -8),... (9, -1)]
I could work out the details, but I think you should do that yourself - with a small test case. And skip that initial copyto, that just hides errors in the iteration. Print the details, not just summary statistics from large random arrays.
And in the long run you don't want to use an iteration like this. You want to do the permutation with one indexing call. But first get this version working correctly.

Understanding PsychoPy's data logging

I have a test PsychoPy Builder script that I am using to investigate some counter-intuitive behaviour. The structure is four routines:
"Init", not in a loop, the following code in "Begin Experiment":
x = 0
y = 0
z = 0
foo = [0, 0, 0]
"One", in a loop, the following code in "End Routine":
x = x + 1
foo[0] = foo[0] + 1
thisExp.addData("x", x)
thisExp.addData("y", y)
thisExp.addData("z", z)
thisExp.addData("foo", foo)
"Two", in a loop, the following code in "End Routine":
y = y + 2
foo[1] = foo[1] + 2
thisExp.addData("x", x)
thisExp.addData("y", y)
thisExp.addData("z", z)
thisExp.addData("fooY", foo[1])
thisExp.addData("foo", foo)
"Three", in a loop, the following code in "End Routine":
z = z + 3
foo[2] = foo[2] + 3
thisExp.addData("x", x)
thisExp.addData("y", y)
thisExp.addData("z", z)
thisExp.addData("foo", foo)
There is no other code, no other components. The routines "One", "Two", and "Three" form a loop in that order executed five times. The relevant columns of the CSV output file are as follows:
trials.thisRepN trials.thisTrialN trials.thisN trials.thisIndex x y z foo fooY
0 0 0 0 1 2 3 [5, 10, 15] 2
1 0 1 0 2 4 6 [5, 10, 15] 4
2 0 2 0 3 6 9 [5, 10, 15] 6
3 0 3 0 4 8 12 [5, 10, 15] 8
4 0 4 0 5 10 15 [5, 10, 15] 10
Is this the expected output? If so, why? Note that the individual variables, x, y, and z, are displaying updated values each time through the loop (at the end of the loop), while the list foo shows only the final value after the loop iterates all five times, but it shows this in every line. But calling out individual elements of the list displays as individual variables do.
What is the logic and rationale behind this?
Is there a way to make the list output perform as the others do?
Is there a way to force the output to capture/display any of these variables as they are when the addData() is invoked rather than waiting until the end of the loop?
I think I know what is going wrong here. It's probably because python assigns by reference rather than copy. This is explained in detail elsewhere but briefly,
original = [1, 2]
new = original # new is simply a reference to original! It is not a copy.
new[0] = 'Oops' # original is now ['Oops', 2] as is new (which is just a reference or pointer
In your case, the TrialHandler receives the reference, which simply points to the "foo" variable which is updated throughout the experiment. Since the log is only saved in the end of the experiment, all the rows in "foo" now points to the "foo variable" which now holds the value [5, 10, 15].
This assignment-by-reference can be extremely beautiful and handy, but sometimes cause headache like in your example. It applies to all python mutables: lists, dicts, functions, and classes. But not for immutables, like numbers, tuples and strings! That's why your script works for digits but not for the list.
There are different solutions. The simplest is probably to replace the addData calls with thisExp.addData("foo", tuple(foo)) which converts the mutable list to an immutable tuple. One can also do thisExp.addData("foo", [x for x in foo]). A more all-round solution for all kinds of objects is to run import copy in the beginning of the experiment and then add data like thisExp.addData("foo", copy.copy(foo)) in the other codeblocks (if you have a complicated object, use copy.deepcopy instead).