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 2.7.8.3.1 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