Home   Archive   Permalink

Inserting at random positions in a block

This might be a very simple question but I'm having a very hard time trying to solve it.
I am trying to insert a character at random inside a block. I know that each block has a position marker, that I can move with instructions like: tail, head, next, skip and so on.
Say I have the block
>> blk: [7 10 2 8 1]
the instruction “at” should set the index of the block at the designated item in the block, so
>> at blk 3
should set the index at the number 2. Of course, I will want the number used with “at” to be generated randomly, but let's leave that for another day.
Now, the instruction “insert” should add a new element at the current position, so:
>> insert blk “*”
should look like: [7 10 “*” 2 8 1]
instead I get
== [7 10 2 8 1]
but if I probe blk I get:
== [“*” 7 10 2 8 1]
showing that the instruction inserted the “*” at the head, moved the index one position and returned the block, so if I ask:
>>head blk
we get
== [“*” 7 10 2 8 1]
I get a similar experience with “skip”:
>> skip blk 3
>> insert blk “$”
gives me not [“*” 7 “$” 10 2 8 1] but
== [“*” 7 10 2 8 1]
>> head blk
== [“$” “*” 7 “$” 10 2 8 1]
The use of refinements is not being kinder with me:
>> insert/part blk “#” 5
== [“#” “$” “*” 7 10 2 8 1]
The first glimmer of hope comes with:
>> blk: [7 10 2 8 1]
>> blk: at blk 3 insert blk “*”
== [2 8 1]
>> head blk
== [7 10 “*” 2 8 1]
I would appreciate any insight on as how to properly insert elements at random access positions, why I am getting this behavior and how does the final example work.
Thanks in advance...

posted by:   Brother Damian       26-Feb-2016/15:38:39-8:00

(Those stupid curly quotes should be abondoned from all charsets in this world. ;-) )
>> blk: [7 10 2 8 1]
>> blk: at blk 3
this sets blk to be positioned at position 3. The two positions before that are still part of the series but the index is now pointing at the third element.
>>insert blk "*"
This now inserts before the indexed position.
>> head blk
most of the time I use this as blk: head blk to set the index back to the head position, or in our terms of understanding, the first one.
Getting any clearer?

posted by:   iArnold       26-Feb-2016/16:04:38-8:00

> Of course, I will want the number used with “at” to be generated randomly, but let's leave that for another day.
Here's one way to do that:
     blk: at head blk random/secure length? blk
Now you can do the insert, and (per iArnold's short tutorial) see the full block again:
     insert blk "*"
     probe head blk

posted by:   Sunanda       27-Feb-2016/1:55:27-8:00

Thanks iArnold for describing what's happening in the algorithm that seems to work. I would like to understand better the syntax: I though that
>> at blk 3
would have been enough to set the pointer in blk, like it seems to happen with
>> head blk
but no, it doesn't. Instead I have to do some kind of assignment with the colon operator:
>> blk: at blk 3
Why is this?
However, this solution is not really working. That or my reasoning is flawed. In order to insert at random my item into the block I tried this but had the following unexpected result:
blk: copy []
blk: [19 20 9 3 17]
item: “*”
n: random 6
prin "n= " print n
blk: at blk n insert blk item
head blk
probe blk
and got the following:
n= 4
["*" 3 17]     ; (now, this does not happen all the time, but I do run the same code all the time!)
That was unexpected, so I tried
>> head blk
== [19 20 9 "*" 3 17]
Aha! But did the “head” instruction change the index?
>> index? blk
== 4
Apparently not. Following Sunanda's very smart code, it seems that, again one needs to “assign” the index position with the colon:
>> blk: head blk
However, this gave me:
>> index? Blk
== 4
with the consequence that if I request
>> print blk/1
== *
which means that I was able to insert the item in my block but now I don't know how to use the entire block, including the first items.
Is this “assignment” correct? Is this a proper way for inserting an item in a block or am I bending the purpose of code? Why am I getting inconsistent results? Is there an alternative way to do this?
Could this be an entry for the Beginner's Gotchas Tutorial?
I got some consistent results with:
blk: [19 20 9 3 17]
n: random 5
item: “*”
forall blk [ if n = index? blk [ insert blk item ]]
which would not be so offensive with a small block like in the example but would not work in other contexts as it requires block traversal.
So, to sum up: is this “assignment”, as in:
>> blk: at blk 3
>> blk: head blk
the proper syntax and the proper solution for the problem at hand? And if so, why is the index not updated? Also, what if I use another block for the assignment, as in:
>> blk: at other-blk 3
(just in case, I am using REBOL/View 1-Jan-2011)
Thanks again for your help.

posted by:   Brother Damian       27-Feb-2016/11:03:52-8:00

I think you may be missing a neat concept about blocks: A block is not just a aeries of items; it is also an "internal pointer" to the "current" item - think of it like a cursor if that terminology works for you.
These examples attempt to show what happens when you change the internal pointer in various ways:
blk: [1 2 3 4 5 6]
probe blk ; shows original block
probe next blk ; shows block from 2nd item
probe at blk 4 ; shows block from 4th item
probe blk ; shows original block -- internal pointer has not changed
blk: next blk ; change internal pointer to 2nd item
probe blk ; shows block from 2nd item
probe head blk ; shows original block
probe at blk 4 ; shows block from 5th item
blk: head blk ; reset internal pointer to start of block
probe blk ; what do you expect to see?

posted by:   Sunanda       27-Feb-2016/18:27:54-8:00

Dear Sunanda:
I would expect to see the block from the first item forth, but as the transcription of the little experiment in my previous post shows, this didn't happen.
I am aware of the pointer in blocks, which is the basis of my code; but I am not finding a correlation between what I expect to see from what actually happens. This could be because of improper syntax or because there is some conceptual element I am missing. In any event, I want to insert an item at random into a block (hopefully with out having to traverse it) and believe that the "internal pointer" is the right way to do it but my implementations are not working. But I am not really asking for just a solution, I would appreciate an explanation that would help me understand the hows and whys that can help me make better predictions (and code) later.
Thanks for any help.

posted by:   Brother Damian       1-Mar-2016/8:57:35-8:00

>the instruction “at” should set the index of the block
It's more like creating a new pointer to the block.
Skip and head works the same way. Sorry if this already was clear.
>> blk: [7 10 2 8 1]
== [7 10 2 8 1]
>> insert at blk 3 "*"
== [2 8 1] ;pos after insert
>> blk
== [7 10 "*" 2 8 1]

posted by:   Gorf       1-Mar-2016/21:02:25-8:00

As Gorf suggests, an approach to the mental model is to think of the "name" of the block as being both the variable name AND the current position:
B: copy [1 2 3 4] ;defines a block called B positioned at its head
at B 3 ; displays what is at position 3 of the block without changing the "implicit" pointer
B: at B 3 ;; changes the implicit pointer to be at position 3 of the block
print B ;; now prints from position 3 without changing the implicit pointer
print head B ;; prints from the start of B without changing the implicit pointer
B: head B ;; resets the pointer to the start of the block
A: at B 3 ;; creates another pointer ....
b/3 = a/1 ;; Yes it does!
insert a 99 ;; is the same as insert at B 3 99

posted by:   Sunanda       4-Mar-2016/7:02:20-8:00

Brother Damian:
1) a block! models the comp sci concept of an array
2) a block! can have 0 to n values
3) an index into a block! is an integer representing "the address" of interest
4) a block! start at index 1
Key Idea #1: the RVC stores a value at virtual memory location of the index
>> b: [7 10 2 8 1]
== [7 10 2 8 1]
like this in p-code and many languages:
b[1] = 7; b[2] = 10; b[3] = 2; b[4] = 8; b[5] = 1
Carl designed REBOL to be syntax sparse / free so you don't access block!(s), aka arrays, like you would in syntax heavy languages.
Key Idea #2: Whatever C representation the RVC uses to model a block! structure, it must have a "slot" that keeps an integer to track "the view," i.e., from the current index to the tail. It must have a slot for the current view name.
The RVC keeps the entire block! regardless of its view name.
Key Idea #3: Whenever you or your "code" (in REBOL, it's really all data, ask Carl), introduce an expression, which the RVC can evaluate to a value, it keeps that on it's memory system (however Carl designed it — heap, stack, whatever).
So, if you do this:
>> [7 10 2 8 1]
== [7 10 2 8 1]
It's there in memory. However, you have no obvious handle to access it.
The RVC keeps the entire block! regardless of its view name.
Key Idea #4: any block! has a head item, a last item, a head position and n other positions and a tail position. The nth position of n positions is the last item position.
>> e: []
== []
>> head? e
== true
>> tail? e
== true
>> equal? head? e tail? e
== true
>> same? head? e tail? e
== true
>> attempt [last e]
;; there is nothing there
>> attempt [last e]
== none
>> attempt [first e]
== none
Key Idea #5:
>> b: [7 10 2 8 1]
== [7 10 2 8 1]
You can ask the RVC to look anywhere without tagging the view with a name
;; change the view but not the view name
;; get it?
>> tail? tail b
== true
>> head? b
== true
>> b
== [7 10 2 8 1]
Key Idea #6:
You can ask the RVC to tag any view of the block! it has (Key Idea #) regardless of what it once was named.
;; move the view and the view name
>> b: tail b
== []
>> length? b
== 0
>> tail? b
== true
>> head? b
== false
>> b: head b
== [7 10 2 8 1]
>> head? b
== true
> b: [7 10 2 8 1]
== [7 10 2 8 1]
Key Idea #7
You can have handles tag the same block! in memory when such a block! has a name
>> c: :b
== [7 10 2 8 1]
>> b: tail b
== []
>> c
== [7 10 2 8 1]
Key Idea #8
If you ask the RVC to change the view (Key Idea #5) and tag that view (Key Idea #6), it still has the entire block! as it was first defined (Key Idea #3).
The view names no long name the same view.
;; names are tagging different bits (views) of memory
>> same? b c
== false
;; names are tagging different bits (views) of memory
>> equal? b c
== false
Reset to the same view.
;; names are tagging same bits (views) of memory
>> b: head b
== [7 10 2 8 1]
>> same? b c
== true
Key Idea #9
Because the RVC indexes block!(s) by integers, you can tell the RVC to "iterate" over any block!
;; FOR 'word start end bump body
for j 1 length? b 1 [
    print b/:j
Key Idea #10: The RVC has slicker, "REBOL-ISH" ways to do the same:
forall b [print b/1]
foreach j b [print join "b " j ]
;; dumb for skip = 1 but works
forskip b 1 [print b/1]
That is part of blockology.
Discover the secrets of REBOL by reading my work:
The RVC, REBOL and Red Enlightenment through RVC Zen
at timeserieslord.github.io/rvc/

posted by:   Time Series Lord       29-Sep-2016/17:15:44-7:00