Mailing List Archive: 49091 messages
  • Home
  • Script library
  • AltME Archive
  • Mailing list
  • Articles Index
  • Site search
 

Associative data store

 [1/41] from: joel::neely::fedex::com at: 14-Sep-2000 16:01


The proposed implementation below addresses separation of key/value spaces and tries to take advantage of REBOL built-ins for performance wherever feasible. Critiques and comments welcome! -jn- ===============(begin code listing)================== REBOL [ Title: "Minimal Associative Data Store" File: %assoc.r Date: 14-Sep-2000 Author: "Joel Neely" Purpose: { Quick, minimal implementation of a data store that associates arbitrary values with (string!) keys. } ] assoc: make object! [ _keys: copy [] _vals: copy [] clear: func [] [_keys: copy [] _vals: copy []] clear?: func [] [empty? head _keys] count?: func [] [length? _keys] new: func [/local r] [r: make assoc [] r/clear r] put: func [k [string!] v [any-type!] /local p] [ either none? p: find _keys k [ append _keys k append _vals v ][ change at _vals index? p v ] v ] get: func [k [string!] /local p] [ either none? p: find _keys k [ none ][ pick _vals index? p ] ] keys: func [] [copy _keys] ] =================(end code listing)================== This (minimal) implementation can be used as follows: =================(begin transcript)>> do %assoc.r
>> phonelist: assoc/new >> phonelist/clear?
== true
>> phonelist/put "Bill" "555-1111"
== "555-1111"
>> phonelist/put "Al" "555-2222"
== "555-2222"
>> phonelist/put "George" "555-3333"
== "555-3333"
>> phonelist/put "Dick" "555-4444"
== "555-4444"
>> phonelist/get "Al"
== "555-2222"
>> phonelist/count?
== 4
>> phonelist/keys
== ["Bill" "Al" "George" "Dick"]
>> foreach who phonelist/keys [print [who "^-" phonelist/get who]]
Bill 555-1111 Al 555-2222 George 555-3333 Dick 555-4444
>> foreach who sort phonelist/keys [print [who "^-" phonelist/get who]]
Al 555-2222 Bill 555-1111 Dick 555-4444 George 555-3333
>> privatelist: phonelist/new >> privatelist/count?
== 0
>> >> foreach who head reverse sort phonelist/keys [
[ print [who "^-" phonelist/get who] [ ] George 555-3333 Dick 555-4444 Bill 555-1111 Al 555-2222
>>==================(end transcript)===================
Enjoy! -jn- -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] print to-string debase/64 decompress #{ 789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}

 [2/41] from: bobr:dprc at: 14-Sep-2000 13:07


excellent! I have often wondered why select mixes keyspace with valuespace. - anyone want to try a 'hash based version ? - anyone want to make a /remove refinement ? At 04:01 PM 9/14/00 -0500, [joel--neely--fedex--com] wrote:
>The proposed implementation below addresses separation of key/value >spaces and tries to take advantage of REBOL built-ins for performance >wherever feasible. Critiques and comments welcome! > >-jn- >
;# mailto: [bobr--dprc--net]

 [3/41] from: rebol:keithdevens at: 14-Sep-2000 14:06


I'm very impressed! This seems like it'll be really useful. Just wondering how performance will be. :) I still want something like this built into the language. Also, that way we could use built ins like 'length? on it. Hmm... this brings up another question. There's no way to do any kind of operator overloading in Rebol, so that we *could* use 'length? on this data structure, is there?

 [4/41] from: joel:neely:fedex at: 14-Sep-2000 19:18


Silly me! Thanks for catching the oversight. [bobr--dprc--net] wrote:
> - anyone want to make a /remove refinement ? >
================================================================ REBOL [ Title: "Minimal Associative Data Store" File: %assoc.r Date: 14-Sep-2000 Author: "Joel Neely" Purpose: { Quick, minimal implementation of a data store that associates arbitrary values with (string!) keys. } ] assoc: make object! [ _keys: copy [] _vals: copy [] clear: func [] [_keys: copy [] _vals: copy []] clear?: func [] [empty? head _keys] count?: func [] [length? _keys] new: func [/local r] [r: make assoc [] r/clear r] put: func [k [string!] v [any-type!] /local p] [ either none? p: find _keys k [ append _keys k append _vals v ][ change at _vals index? p v ] v ] get: func [k [string!] /local p] [ either none? p: find _keys k [ none ][ pick _vals index? p ] ] delete: func [k [string!] /local p v] [ either none? p: find _keys k [ none ][ k: pick _vals p: index? p remove at _keys p remove at _vals p k ] ] keys: func [] [copy _keys] ] ================================================================ -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] print to-string debase/64 decompress #{ 789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}

 [5/41] from: joel:neely:fedex at: 14-Sep-2000 19:32


[rebol--keithdevens--com] wrote:
> ... Just wondering how performance will be. :) >
That was the motivation for using paired blocks rather than interleaving the keys and values in a single block. Notice that all of the heavy lifting is still done by find , remove , and change , which are all primitives (and presumably heavily optimized... right RT? ;-) The other built-in, append , is a VERY thin mezzanine wrapper onto insert , which IS primitive. so I think performance will be tolerable. The main overhead is function entry/exit (I suspect) which is unavoidable if we are to add any functionality at all. The main issue is to avoid loops in high-level code. If I had used interleaved keys and values, get would have to be written something like the following: ;!!! WARNING: UNTESTED CODE FRAGMENT !!! assoc: make object! [ _kvpairs: copy [] ; ; etc... ; get: func [t [string!] / local k v] [ foreach [k v] _kvpairs [ if k = t [return v] ] none ] ; ; etc... ; ] which puts real work (proportional to the size of the store) up into interpreted code. That's why I avoided it.
> I still want something like this built into the language. Also, that way we > could use built ins like 'length? on it. > > Hmm... this brings up another question. There's no way to do any kind of > operator overloading in Rebol, so that we *could* use 'length? on this data > structure, is there? >
Your wish is my command! (At least, this once! ;-) ================================================================ REBOL [ Title: "Minimal Associative Data Store" File: %assoc.r Date: 14-Sep-2000 Author: "Joel Neely" Purpose: { Quick, minimal implementation of a data store that associates arbitrary values with (string!) keys. } ] assoc: make object! [ _keys: copy [] _vals: copy [] clear: func [] [_keys: copy [] _vals: copy []] empty?: func [] [system/words/empty? head _keys] length?: func [] [system/words/length? _keys] new: func [/local r] [r: make assoc [] r/clear r] put: func [k [string!] v [any-type!] /local p] [ either none? p: find _keys k [ append _keys k append _vals v ][ change at _vals index? p v ] v ] get: func [k [string!] /local p] [ either none? p: find _keys k [ none ][ pick _vals index? p ] ] delete: func [k [string!] /local p v] [ either none? p: find _keys k [ none ][ k: pick _vals p: index? p remove at _keys p remove at _vals p k ] ] keys: func [] [copy _keys] ] ================================================================ -jn- -- ; Joel Neely [joel--neely--fedex--com] 901-263-4460 38017/HKA/9677 REBOL [] print to-string debase/64 decompress #{ 789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}

 [6/41] from: rebol:techscribe at: 14-Sep-2000 13:37


Hi Joel, Nice. you wrote:
>Critiques and comments welcome!
With respect to the line:
> new: func [/local r] [r: make assoc [] r/clear r]
I think it would be safer to use self instead of assoc new: func [/local r] [r: make self [] r/clear r] ^^^^ 2. An alternative: assoc: [keys [] values []] is-assoc?: func [assoc [block!]] [ all [equal? length? assoc 4 find assoc 'keys find assoc 'values] ] contains-key?: func [assoc [block!] key [any-type!] ] [ all [is-assoc? assoc find assoc/keys key] ] assoc-add: func [assoc [block!] candidates [block!] /local found] [ if is-assoc? assoc [ foreach [key value] candidates [ either found: contains-key? assoc key [ insert at assoc/values index? found value ][ insert assoc/keys key insert assoc/values value ] ] return true ] return false ] assoc-get: func [assoc [block!] key [any-type!] /local found] [ if found: contains-key? assoc key [ return pick assoc/values index? found ] return none ]
>> phonelist: copy/deep assoc
== [keys [] values []]
>> assoc-add phonelist [Bill "555-1111"]
== true
>> assoc-add phonelist [Al "555-2222"]
== true
>> assoc-add phonelist [George "555-3333"]
== true
>> assoc-add phonelist [Dick "555-4444"]
== true
>> assoc-add phonelist [Jane "555-3322" Judy "555-2233"]
== true
>> assoc-get phonelist 'Bill
== "555-1111"
>> assoc-get phonelist 'Dick
== "555-4444"
>> assoc-get phonelist 'George
== "555-3333"
>> assoc-get phonelist 'Jane
== "555-3322"
>> assoc-get phonelist 'Judy
== "555-2233"
>> assoc-get phonelist 'Al
== "555-2222"
>> foreach who sort copy phonelist/keys [print [who assoc-get phonelist who]]
Al 555-2222 Bill 555-1111 Dick 555-4444 George 555-3333 Jane 555-3322 Judy 555-2233 Looks to me like it accomplishes pretty much the same thing
> separation of key/value spaces
without the additional overhead of an object (function code duplication for each list). In addition I see the advantage of being able to effortlessly add multiple items by including them in a block (batch adding ;-). At 04:01 PM 9/14/00 -0500, you wrote:
>The proposed implementation below addresses separation of key/value >spaces and tries to take advantage of REBOL built-ins for performance
<<quoted lines omitted: 84>>
> 789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC > B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [7/41] from: rsnell:webtrends at: 14-Sep-2000 14:10


Great stuff from both of you - I am thinking of changing my INI file handling code to one of these methods (where I have a hash of hashes so that a section value is really itself an associative array). But Elan, what do you mean when you say that there is a problem with function code duplication using the object approach? I haven't used a lot of Rebol objects yet, but my OOP experience tells me (yes I know I'm supposed to forget it about that!) that there is only one instance of code for all objects based on a base template. TIA, Rodney

 [8/41] from: rebol:techscribe at: 14-Sep-2000 14:34


Hi Joel, you wrote:
>[rebol--keithdevens--com] wrote: >>
<<quoted lines omitted: 17>>
> none > ]
If your only concern is avoiding loops, and that is why you are not using a single block to contain both keys and values, then why not use a single block in combination with the path notation? assoc: make object! [ _kvpairs: copy [] get: func [t [string!] /local path] [ path: make path! compose [_kvpairs (t)] return path ] That should do it. You can do the whole thing with paths, without supplying any new functions or objects:
>> phonelist: make block! 10
== []
>> insert phonelist [Jim "555-3333"]
== []
>> insert phonelist [Dick "555-2222"]
== [Jim "555-3333"]
>> insert phonelist [Judy "555-4444" Jane "555-5555"]
== [Dick "555-2222" Jim "555-3333"]
>> insert phonelist [Bill "555-1111"]
== [Judy "555-4444" Jane "555-5555" Dick "555-2222" Jim "555-3333"]
>> insert phonelist [Al "555-9999"]
== [Bill "555-1111" Judy "555-4444" Jane "555-5555" Dick "555-2222" Jim 555-3333 ]
>> phonelist/Bill
== "555-1111"
>> phonelist/Dick
== "555-2222"
>> phonelist/Jim
== "555-3333"
>> phonelist/Judy
== "555-4444"
>> phonelist/Al
== "555-9999"
>> phonelist/Jane
== "555-5555"
>> foreach [who phone] sort/skip copy phonelist 2 [
[ print [who phone] [ ] Al 555-9999 Bill 555-1111 Dick 555-2222 Jane 555-5555 Jim 555-3333 Judy 555-4444
>; >; etc...
<<quoted lines omitted: 63>>
> 789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC > B6F4F574CFC888342AC949CE74B50500E1710C0C24000000}
;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [9/41] from: rebol:techscribe at: 14-Sep-2000 14:54


Hi Rodney, I believe REBOL makes a new copy of functions for each derived object. Let me introduce the players: A root object o, a function f, and a derived object p:
>> o: make object! [f: func [] [print "a"] ] >> p: make o []
At this point the two objects are look-alikes:
>> probe o
make object! [ f: func [][print "a"] ]
>> probe p
make object! [ f: func [][print "a"] ] Let us replace the string "a" by the string "b" in p's function f
>> change at second get in p 'f 2 "b"
== [] Were we successful?
>> probe p
make object! [ f: func [][print "b"] ] Yes. Was the function f in the parent object o also modified?
>> probe o
make object! [ f: func [][print "a"] ] No! Apparently modifications to the inherited function f in p do not propagate to the f function in the parent object o, ergo the two functions are independent of each other. At 02:10 PM 9/14/00 -0700, you wrote:
>Great stuff from both of you - I am thinking of changing my >INI file handling code to one of these methods (where I have
<<quoted lines omitted: 190>>
> http://www.REBOLpress.com > visit me at http://www.TechScribe.com
;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [10/41] from: rebol:techscribe at: 14-Sep-2000 14:57


Oh, shucks, a bug:
>assoc-add: func [assoc [block!] candidates [block!] /local found] [ > if is-assoc? assoc [ > foreach [key value] candidates [ > either found: contains-key? assoc key [ > insert at assoc/values index? found value
The line
> insert at assoc/values index? found value
Should be change at assoc/values index? found value
> ][ > insert assoc/keys key
<<quoted lines omitted: 5>>
> return false >]
To quote Joel, "silly me" :-). ;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [11/41] from: allen:rebolforces at: 15-Sep-2000 8:24


This is a multi-part message in MIME format. ------=_NextPart_000_002F_01C01EEE.52DD2BD0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Digging through my own archive. I see that I wrote one last year to behave a bit more like the collection object in VB. This also allows items to be added and removed with an index as well, and test for existence. I never got to thoroughly testing it though, so there are most likely many ways to fix/improve it. So if anyone wants to look at combining the two, you are quite welcome too. Cheers, Allen K ------=_NextPart_000_002F_01C01EEE.52DD2BD0 Content-Type: text/x-rebol; name="collection.r" Content-Transfer-Encoding: quoted-printable Content-Disposition: attachment; filename="collection.r" REBOL [ Title: "Collection Object" Author: "Allen Kamp" Date: 11-Sep-1999 Email: [allenk--powerup--com--au] Purpose: {To provide an object similar to the VB collection object.} Notes: {Should make attributes and value lists read only, Also add a method to return a paired block, for iteration, and a clone method} Usage: {
>> col: make collection [] >> col/set "Apple" "Green" >> col/set "Orange" "Orange" >> col/set "Grapes" "Purple" >> col/count
== 3
>> col/get "Apple"
== "Green"
>> col/set "Apple" "Red" >> col/get "Apple"
== "Red"
>> col/exists? "Apple" ;--Return the index or else false
== 1
>> col/get-item 1
== "Red"
>> col/remove "Apple" >> col/get "Apple"
== none ;-- if you want to add to the beginning of the list col/set/pos "Apple" "Granny Smith" 1 ;-- to return the list of attributes or values col/attributes col/values } ] collection: make object! [ values: make block! [] 30 attributes: make block! [] 30 count: func [][length? attributes] exists?: func [ attribute [any-string!] /local mark ][ either found? mark: find attributes attribute [return (index? mark)][return false] ] remove-all: func [][attributes: make hash! [] 30 values: make block! [] 30 exit] remove-item: func [ key [any-string! integer!] /local index ][ either integer? key [ index: key ][ if not index: exists? key [exit] ] remove at attributes index remove at values index exit ] get: func [ {Returns the value for the key or index. Returns none if does not exist} key [any-string! integer!] {Attribute name string or an index} /local index ][ if not integer? key [ either index: exists? key [ key: index ][ key: 0 ] ] return pick values key ] set: func [ key [any-string!] {Attribute name string} value /pos position [integer!] {Specify a position in the list} /local index ][ either pos [ insert at attributes position key insert/only at values position value exit ][ either index: exists? key [ change/only at values index value exit ][ insert tail attributes key insert/only tail values value exit ] ] ] ] ------=_NextPart_000_002F_01C01EEE.52DD2BD0--

 [12/41] from: ryanc:iesco-dms at: 14-Sep-2000 15:21


This little booger might be handy too. Though it has one peculiarity, dont use blocks as keys when values might match the contents of the block key. assoc: make object! [ list: copy [] clear: func [] [list: copy []] set: func [key value] [ append list key append/only list reduce [value]] get: func [key /rv] [ first select list key ] unset: func [key] [ remove/part find t key 2 ] ] --Ryan Ryan Cole Programmer Analyst www.iesco-dms.com 707-468-5400 The Tao that can be expressed is not the eternal Tao. -Lao Tzu

 [13/41] from: rebol:keithdevens at: 14-Sep-2000 19:13


I really like the path idea. Is there any way to emulate an associative array without having to make a special object type? Very unfortunately, Rebol doesn't let you just do things like: assoc/key: "value" (if assoc/key doesn't actually exist yet) is there any way to cheat and do something like: (fake example that doesn't work) assoc: make hash! [] change assoc/key "dude" -------------------------------------------------------------------- It would be really really nice if RT could give us something like this (hint hint): assoc: make associative! [] assoc/key: "value" 'first could give us the keys and 'second could give us the values Bonus is, it doesn't require any new syntax... no funky assoc{'key'} or anything. :) Keith

 [14/41] from: ryanc:iesco-dms at: 14-Sep-2000 16:57


FYI: Not quite there, but using the one I just posted allows you to do this:
>> assoc/set 'the "dog"
== [the ["dog"]]
>> assoc/get 'the
== "dog"
>> assoc/list/the
== ["dog"]
>>
[rebol--keithdevens--com] wrote:
> I really like the path idea. Is there any way to emulate an associative > array without having to make a special object type?
<<quoted lines omitted: 58>>
> > visit me at http://www.TechScribe.com > >
-- Ryan Cole Programmer Analyst www.iesco-dms.com 707-468-5400 The problem of language here are really serious. We wish to speak in some way about the structure of the atoms . . . But we cannot speak about atoms in ordinary language. -W. Heisenberg

 [15/41] from: rebol:techscribe at: 14-Sep-2000 18:28


Hi Keith, You could use the & function like this:
>> assoc: [a 3]
== [a 3]
>> print mold assoc
[a 3]
>> assoc/a
== 3 Now let's add a new key / value pair using &, the new key will be called new-key
>> & assoc/new-key 4
== [a 3]
>> assoc/new-key
== 4
>> print mold assoc
[new-key 4 a 3] And another new key/value pair:
>> & assoc/zz "yet another new key/value pair."
== [new-key 4 a 3]
>> assoc/zz
== "yet another new key/value pair."
>> print mold assoc
[zz "yet another new key/value pair." new-key 4 a 3] We can also add deeper levels:
>> assoc: [a 1]
== [a 1]
>> print mold a
== [a 1]
>> assoc/a
== 1 Let's create a two-level new path that we will address as a/b/c (where b/c is the new path in a that we are creating)
>> & assoc/b [c 3]
== [a 1]
>> print mold assoc
[b [c 3] a 1]
>> assoc/b
== [c 3]
>> assoc/b/c
== 3 Now for the & function that makes it possible: &: func ['_p [path!] _v /local _b] [ _b: copy/part :_p (subtract length? :_p 1) if value? :_b [ insert _b reduce [last :_p _v] ] ] At 07:13 PM 9/14/00 -0400, you wrote:
>I really like the path idea. Is there any way to emulate an associative >array without having to make a special object type?
<<quoted lines omitted: 58>>
>> visit me at http://www.TechScribe.com >>
;- Elan [ : - ) ] author of REBOL: THE OFFICIAL GUIDE REBOL Press: The Official Source for REBOL Books http://www.REBOLpress.com visit me at http://www.TechScribe.com

 [16/41] from: agem:crosswinds at: 15-Sep-2000 5:19


[rebol--keithdevens--com] wrote on 14-Sep-2000/19:13:08-4:00

 [17/41] from: agem:crosswinds at: 15-Sep-2000 5:19


[rebol--keithdevens--com] wrote on 14-Sep-2000/19:13:08-4:00
> I really like the path idea. Is there any way to emulate an associative > array without having to make a special object type? >
use different types for key/value. for example, use word! for key, string! for value. this works often, like i have file! as key and numbers (position etc) as values, or simple types as keys and blocks as values etc. 'find checks for type, so find somewhere 'find-me find somewhere "find-me" are different.
> Very unfortunately, Rebol doesn't let you just do things like: > assoc/key: "value"
<<quoted lines omitted: 3>>
> assoc: make hash! [] > change assoc/key "dude"
i use this: now-is: function [ "change value after key, if it is present, otherwise append both" series key value] [here] [ here: find series key either here [change/only next here value] [append series reduce [key value]] ]

 [18/41] from: al:bri:xtra at: 15-Sep-2000 21:22


This is a multi-part message in MIME format. ------=_NextPart_000_04DB_01C01F5B.1A176640 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit I wanted to use integers as keys, so I wrote this up. [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 15/September/2000 ] Encapsulate: function [Value] [Block] [ Block: make block! 1 insert/only Block Value Block ] Associate: function [Block [block!] Key Value] [Index] [ either found? Index: find Block Key [ change/only next Index Encapsulate Value ][ append Block reduce [Key Encapsulate Value] ] Block ] Deassociate: function [Block [block!] Key] [Index] [ if found? Index: find Block Key [ remove/part Index 2 ] Block ] Associated?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ]
>> do %Associate.r >> block: []
== []
>> Associate block 1 "The test is this"
== [1 ["The test is this"]]
>> Associate block 2 [1 2 3]
== [1 ["The test is this"] 2 [[1 2 3]]]
>> associated? block 1
== "The test is this"
>> associated? block 2
== [1 2 3]
>> block/2
== ["The test is this"]
>> deassociate block 2
== [1 ["The test is this"]]
>> deassociate block 1
== [] I don't like 'Encapsulate. Any one know of a better way to do it? Andrew Martin ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_04DB_01C01F5B.1A176640 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 15/September/2000 ] Encapsulate: function [Value] [Block] [ Block: make block! 1 insert/only Block Value Block ] Associate: function [Block [block!] Key Value] [Index] [ either found? Index: find Block Key [ change/only next Index Encapsulate Value ][ append Block reduce [Key Encapsulate Value] ] Block ] Deassociate: function [Block [block!] Key] [Index] [ if found? Index: find Block Key [ remove/part Index 2 ] Block ] Associated?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ] ------=_NextPart_000_04DB_01C01F5B.1A176640--

 [19/41] from: al:bri:xtra at: 15-Sep-2000 22:39


This is a multi-part message in MIME format. ------=_NextPart_000_069A_01C01F65.D37B3940 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit I wrote:
> I don't like 'Encapsulate. Any one know of a better way to do it?
I blame the drugs I'm not taking... Value: reduce [Value] is a far better way of doing it. [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 15/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Value: reduce [Value] either found? Index: find Block Key [ change/only next Index Value ][ append Block reduce [Key Value] ] Block ] Deassociate: function [Block [block!] Key] [Index] [ if found? Index: find Block Key [ remove/part Index 2 ] Block ] Associated?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ]
>> do %associate.r >> block: []
== []
>> Associate block 1 "The test is this"
== [1 ["The test is this"]]
>> Associate block 2 [1 2 3]
== [1 ["The test is this"] 2 [[1 2 3]]]
>> associated? block 1
== "The test is this"
>> associated? block 2
== [1 2 3]
>> block/2
== ["The test is this"]
>> Associate block 'antidisestablishmentarianism [1 "is a long word!" 3]
== [1 ["The test is this"] 2 [[1 2 3]] antidisestablishmentarianism [[1 "is a long word!" 3]]]
>> Associate block 'anti [3 2 1]
== [1 ["The test is this"] 2 [[1 2 3]] antidisestablishmentarianism [[1 "is a long word!" 3]] anti [[3 2 1]]]
>> block/anti
== [[3 2 1]]
>> first block/anti
== [3 2 1]
>> deassociate block 2
== [1 ["The test is this"] antidisestablishmentarianism [[1 "is a long word!" 3]] anti [[3 2 1]]]
>> deassociate block 1
== [antidisestablishmentarianism [[1 "is a long word!" 3]] anti [[3 2 1]]]
>> clear block
== [] Andrew Martin ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_069A_01C01F65.D37B3940 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 15/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Value: reduce [Value] either found? Index: find Block Key [ change/only next Index Value ][ append Block reduce [Key Value] ] Block ] Deassociate: function [Block [block!] Key] [Index] [ if found? Index: find Block Key [ remove/part Index 2 ] Block ] Associated?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ] ------=_NextPart_000_069A_01C01F65.D37B3940--

 [20/41] from: ryanc:iesco-dms at: 15-Sep-2000 11:18


That last little booger I posted didnt let you update values, and crashed when you asked it a stupid question. This updated version lets you update values, and returns none when you ask it about a key it has not encountered: assoc: make object! [ list: copy[] clear: func[][list: copy[]] set: func[key value][ if get key[unset key] append list key append/only list reduce[value] ] get: func[key] [ rv: none error? try [rv: first select list key] :rv ] unset: func [key][remove/part find list key 2] ] You still want to be careful when using block keys. [ryanc--iesco-dms--com] wrote:
> This little booger might be handy too. Though it has one peculiarity, dont use > blocks as keys when values might match the contents of the block key.
<<quoted lines omitted: 12>>
> The Tao that can be expressed > is not the eternal Tao. -Lao Tzu
--ya ya ya Ryan Cole Programmer Analyst www.iesco-dms.com 707-468-5400 The problem of language here are really serious. We wish to speak in some way about the structure of the atoms . . . But we cannot speak about atoms in ordinary language. -W. Heisenberg

 [21/41] from: joel:neely:fedex at: 15-Sep-2000 9:25


[rebol--keithdevens--com] wrote:
> It would be really really nice if RT could give us something like this (hint > hint): > > assoc: make associative! [] > assoc/key: "value" > > 'first could give us the keys > and 'second could give us the values >
Please, no! First, let me quickly point out my own culpability in submitting a QAD that used only string! values as keys, but I would NOT like to have a built-in associative store that only used string! (as in my sketch) or word! (as implied by the above) values as keys. Any data type supported by the language should be acceptable as a key. REBOL shouldn't have any second-class citizens. Second, as long as REBOL is dependent on the set-*! types, the above notation has a serious problem. Suppose I had this-key: ;some complicated expression evaluating to a key this-val: ;some other complicated expression for a value I would then be unable to say assoc/:this-key: this-val Whatever notation might be in a future version of REBOL for associative data stores, it should NOT penalize the use of variables. Third, IMHO it would be VERY bad to force implementation details (such as how or where keys and values are stored) upon the user of the CONCEPT of associative array. The words 'first, 'second, etc. describe position, which is fine if I'm working on a data structure where the order of the elements is the most relevant thing to know. I believe them to be entirely inappropriate when used in a context such as "I want the key values to this associative store. I happen to know that the keys are the first component of its representation (at least in REBOL 7.9) so I'll get them using 'first." Suppose (this is hypthetical, but please look beyond the specifics of the example to the underlying principle) Carl and company figure out a new memory management technique in the course of fixing the use vs. GC bug (hint, hint ;-) and decide to change the internal representation of objects so that the list of words within the object's context is no longer the "first" attribute of the object. How many scripts would break if they made that change? OTOH, suppose we had an interface to objects and functions that would allow one to say fun-context: get-context some-function obj-context: get-context some-object bind-to-context fun-context word-list bind-to-context fun-context word-list etc. In other words, real support for context! as a first-class data type, along with meaningful names for officially sanctioned interfaces to, and operations using, context! values. Wouldn't that be clearer to read, easier to learn, and give RT more opportunities for optimizing/upgrading/tweaking implementations without any concern that doing so would invalidate existing tricky code? -jn-

 [22/41] from: al:bri:xtra at: 16-Sep-2000 10:51


This is a multi-part message in MIME format. ------=_NextPart_000_0281_01C01FCC.0245EB60 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit And here's a version that's shorter and nicer to use. Can any one think of a shorter version? [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 16/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Value: reduce [Value] either found? Index: find Block Key [ either none? Value [ remove/part Index 2 ][ change/only next Index Value ] ][ append Block reduce [Key Value] ] Block ] Associate?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ] Andrew Martin ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_0281_01C01FCC.0245EB60 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 16/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Value: reduce [Value] either found? Index: find Block Key [ either none? Value [ remove/part Index 2 ][ change/only next Index Value ] ][ append Block reduce [Key Value] ] Block ] Associate?: function [Block [block!] Key] [Value] [ Value: select Block Key either none? Value [none] [first Value] ] ] ------=_NextPart_000_0281_01C01FCC.0245EB60--

 [23/41] from: g:santilli:tiscalinet:it at: 16-Sep-2000 18:19


Hello [Al--Bri--xtra--co--nz]! On 15-Set-00, you wrote: A> Encapsulate: function [Value] [Block] [ A> Block: make block! 1 insert/only Block Value Block A> ]
>> encapsulate: func [value] [reduce [value]] >> encapsulate 1
== [1]
>> encapsulate "something"
== ["something"]
>> encapsulate [a block]
== [[a block]] Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [24/41] from: g:santilli:tiscalinet:it at: 16-Sep-2000 18:35


Hello [joel--neely--fedex--com]! On 15-Set-00, you wrote: j> Third, IMHO it would be VERY bad to force implementation j> details (such as how or where keys and values are stored) upon j> the user of the CONCEPT of associative array. The words j> 'first, 'second, etc. describe position, [...] j> Suppose (this is hypthetical, but please look beyond the j> specifics of the example to the underlying principle) Carl and j> company figure out a new memory management technique in the j> course of fixing the "use vs. GC" bug (hint, hint ;-) and j> decide to change the internal representation of objects so j> that the list of words within the object's context is no j> longer the "first" attribute of the object. How many scripts Actually, the list of words doesn't have to be the "first attribute" of an object for FIRST to work. FIRST is an ACTION!, so a "method" in the value (every REBOL datatype has a table of methods that apply to its values). In particular, FIRST is the
>> second :first
== 41 41st function in the table for any value. (Yeah, this is speculation, but its reasonable, isn't it?) Of course, I agree that "first" is not a good name for "get the words of this object". I stongely suggest RT to add:
>> words-of: :first >> values-of: :second
and so on... (using whatever names they find appropriate) j> etc. In other words, real support for context! as a j> first-class data type, along with meaningful names for j> officially sanctioned interfaces to, and operations using, j> context! values. This would be a good thing, too. :-) Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [25/41] from: g:santilli:tiscalinet:it at: 16-Sep-2000 19:09


Hello [Al--Bri--xtra--co--nz]! On 16-Set-00, you wrote: A> And here's a version that's shorter and nicer to use. Can any A> one think of a shorter version? Yup. ;^) associate: func [block [block!] key value] [ head change/only any [ find/tail block key insert tail block key ] reduce [val] ] associate?: func [block [block!] key] [ all [key: select block key first key] ] Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [26/41] from: al:bri:xtra at: 18-Sep-2000 16:19


Gabriele wrote:
> >> encapsulate: func [value] [reduce [value]]
Thanks Gabriele. I realised that this was simpler: reduce [value] Andrew Martin ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/

 [27/41] from: al:bri:xtra at: 18-Sep-2000 16:48


Gabriele wrote:
> Andrew wrote: > A> And here's a version that's shorter and nicer to use. Can any one
think of a shorter version?
> Yup. ;^) > associate: func [block [block!] key value] [
<<quoted lines omitted: 6>>
> all [key: select block key first key] > ]
Thanks Gabriele! I just need to change this line: ] reduce [val] to: ] reduce [value] as there's a stray 'VAL running around in Rebol. Andrew Martin That Val is not my sister! :-) ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/

 [28/41] from: al:bri:xtra at: 18-Sep-2000 20:04


This is a multi-part message in MIME format. ------=_NextPart_000_02F1_01C021AB.A5365720 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Here's an implementation for an Associative Data Store (ADS) that uses only two functions, doesn't require an object per ADS and can use any Rebol value as a key. Comment invited. Thanks to Gabriele for showing how to shorten the 'Associate? function. [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 18/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Index: find Block Key either none? Value [ if found? Index [ remove/part Index 2 ] ][ either found? Index [ change/only next Index reduce [Value] ][ append Block reduce [Key reduce [Value]] ] ] Block ] Associate?: function [Block [block!] Key] [Value] [ all [ Value: select Block Key first Value ] ] ] Andrew Martin ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_02F1_01C021AB.A5365720 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 18/September/2000 ] Associate: function [Block [block!] Key Value] [Index] [ Index: find Block Key either none? Value [ if found? Index [ remove/part Index 2 ] ][ either found? Index [ change/only next Index reduce [Value] ][ append Block reduce [Key reduce [Value]] ] ] Block ] Associate?: function [Block [block!] Key] [Value] [ all [ Value: select Block Key first Value ] ] ] ------=_NextPart_000_02F1_01C021AB.A5365720--

 [29/41] from: joel:neely:fedex at: 18-Sep-2000 6:47


Here's what happened when I tried it:
>> blk: []
== []
>> Associate blk [2 3] 5
== [[2 3] [5]]
>> Associate? blk [2 3]
== none Beg pardon? Also...
>> Associate blk 5 7
== [[2 3] [5] 5 [7]]
>> Associate blk [5] 9
== [[2 3] [5] 5 [9]]
>> Associate? blk 5
== 9
>> Associate? blk [5]
== 9 Hmmm... Can't distinguish 5 from [5] ??
>> Associate? blk reduce [2 3]
== none
>> Associate? blk reduce [[2 3]]
== 5 Aha! Unlike all other data types, an extra [] wrapper is require for block! -type keys? Well, let's check to see if the old merged-key/value-space bug is still present.
>> Associate? blk reduce [[5]]
** Script Error: first expected series argument of type: series pair event money date object port time tuple any-function library struct event. ** Where: all [ Value: select Block Key first Value ] So I can't even check to see if [[5]] (or [5]???) might have been legitimately used as a key? This version still uses find and therefore still "inherits" the buggy behavior when block! data are used as keys. -jn- [Al--Bri--xtra--co--nz] wrote:
> Here's an implementation for an Associative Data Store (ADS) that uses only > two functions, doesn't require an object per ADS and can use any Rebol value > as a key. Comment invited. Thanks to Gabriele for showing how to shorten the > 'Associate? function. >
[code snipped]

 [30/41] from: lmecir:geocities at: 18-Sep-2000 14:24


Hi Andrew, there is a lot of cases, where your functions won't work as expected, eg.: blk: copy [] associate blk [2] 3 associate? blk [2] The other problem is, that your functions won't accept Any-type! values for Key/Value Regards Ladislav

 [31/41] from: rebol:keithdevens at: 18-Sep-2000 10:35


I'm probably going to get beaten up for this :), but if my question is totally absurd, please excuse my ignorance... You seem to put a lot of emphasis on being able to use block!s as keys. Is this really necessary or desired? It seems like an implementation would be easier and/or more efficient if we didn't have to worry about that case. Same for logic! values :) Many other languages get by with just strings for keys, why do we have to be able to use every Rebol data type as a key? Keith

 [32/41] from: petr:krenzelok:trz:cz at: 18-Sep-2000 17:31


----- Original Message ----- From: <[rebol--keithdevens--com]> To: <[list--rebol--com]> Sent: Monday, September 18, 2000 4:35 PM Subject: [REBOL] Associative Data Store Re:(2)
> I'm probably going to get beaten up for this :), but if my question is > totally absurd, please excuse my ignorance... > > You seem to put a lot of emphasis on being able to use block!s as keys. Is > this really necessary or desired? > > It seems like an implementation would be easier and/or more efficient if
we
> didn't have to worry about that case. Same for logic! values :) > > Many other languages get by with just strings for keys, why do we have to
be
> able to use every Rebol data type as a key?
That's true. Even XBase systems work that way. In real - what about any entry form fiels? They are all strings ... and if not, you can convert to string first :-) -pekr-

 [33/41] from: ryanc:iesco-dms at: 18-Sep-2000 10:35


Keith and Pek made me realize the obvious. The main problem with select is we need to use it with two differrent datatypes. Thus so, we can force the key to string and wrap the data with a block. I believe if we convert the string with mold we save data type integrity. I think this solves all problems with using select. --Ryan [petr--krenzelok--trz--cz] wrote:
> ----- Original Message ----- > From: <[rebol--keithdevens--com]>
<<quoted lines omitted: 90>>
> > > [code snipped] > >
-- Ryan Cole Programmer Analyst www.iesco-dms.com 707-468-5400 The problem of language here are really serious. We wish to speak in some way about the structure of the atoms . . . But we cannot speak about atoms in ordinary language. -W. Heisenberg

 [34/41] from: ryanc:iesco-dms at: 18-Sep-2000 11:06


Here is my very subtle mold change applied to Gabriele's script: associate: func [block [block!] key value] [ head change/only any [ find/tail block mold key insert tail block mold key ] reduce [value] ] associate?: func [block [block!] key] [ all [key: select block mold key first mold key] ] I cannot find any bugs, someone else want to try? --Ryan [ryanc--iesco-dms--com] wrote:

 [35/41] from: g:santilli:tiscalinet:it at: 18-Sep-2000 22:05


Hello [Al--Bri--xtra--co--nz]! On 18-Set-00, you wrote: A> Thanks Gabriele! I just need to change this line: A> ] reduce [val] A> to: A> ] reduce [value] Oops! I tested that on the console, with: associate: func [blk key val] ... and missed that 'val when changing the function for the list... :-) A> as there's a stray 'VAL running around in Rebol. Some function that lacks a /local declaration... Regards, Gabriele. -- Gabriele Santilli <[giesse--writeme--com]> - Amigan - REBOL programmer Amiga Group Italia sez. L'Aquila -- http://www.amyresource.it/AGI/

 [36/41] from: joel:neely:fedex at: 18-Sep-2000 18:27


[rebol--keithdevens--com] wrote:
> I'm probably going to get beaten up for this :), but if my question is > totally absurd, please excuse my ignorance... >
The only absurd questions are those that are asked out of malice or not asked out of timidity. ;-) I may have strong opinions on what I'd like to be able to do in my own programs, but certainly don't want that to come across as negative value judgements on anyone who wishes to write in a different style.
> You seem to put a lot of emphasis on being able to use block!s as keys. Is > this really necessary or desired? >
Well, in terms of strictly "necessary", we could just write everything in tcl, where all data are strings (even data structures). However, REBOL gives us this really nice collection of various data types. Why NOT be able to use them? As the only thing really necessary for looking up a key is to do an equality test, why shouldn't keys be able to come from any data type for which the concept of "equal" makes sense? Also, as one of my co-workers pointed out to me, a block! is a generic container into which I'm allowed to put any kind of REBOL data I wish. If find (for example) is defined to work on blocks, then why shouldn't it work on blocks that contain anything blocks are allowed to contain (such as other blocks)? In terms of "desired", I certainly desire that capability! Let me give an example: Suppose I have a file of data on school children, which includes age and grade level for each student. Now suppose I'm asked to cross-tabulate age and grade level for some report. This means I need a set of counters, where each one corresponds to a specific combination of age and grade. It would be very pleasant, IMHO, to be able to write something like the following sketch: age-grade-tab: assoc/new foreach studentrecord read/lines %studentdemographics.data [ age: get-age studentrecord grade: get-grade studentrecord a-g: reduce [age grade] ; the key IS the combination! age-grade-tab/put a-g 1 + any [age-grade-tab/get a-g 0] ] Now someone may ask why I didn't just use a two-dimensional array, with age and grade as subscripts. A couple of reasons immediately come to mind: 0) A counter is identified by a combination of two facts: age and grade. REBOL provides me with a handy datatype for representing compound values: the block! Why shouldn't I use it? 1) Such an array would be very sparse! As most of the values are clustered along a narrow diagonal band, it would be nice to limit my storage requirements to age/grade combinations that actually exist. (Please remember that this is a small example of a more general concern. I'm only illustrating the fact that arrays are often wildly space-inefficient; I'm sure you can all come up with many examples that are even more extreme, such as weight in grams versus height in centimeters, etc.) 2) Who says that grade is an integer? Perhaps the coding scheme is that "K" is kindergarten, 1-8 are grade numbers, "Fr" "So" "Jr" "Sr" are the last four levels of high school, "GED" high-school equivalent coursework for adults, and "AE" is adult education courses for high school diploma holders. In this case we not only can't use the grade as a numerical index, but now our ranges of values for both age and grade have become much larger, greatly aggravating the sparse-array problem above. 3) Notice that the code sketch above is unaffected by changes in these issues. If I originally wrote the code above only for an elementary school (ages 6-11, grades 1-6) and was suddenly asked to produce the same report for an entire traditional system (ages 4-18, grades 1-12) or a non-traditional school (with the non-numeric grade codings and ages 4-90), the above code wouldn't break. Isn't writing generalized code that doesn't break a good thing to do? Turning the output side of the report, I can start with something as simple as foreach k age-grade-tab/keys [ print [k ":" age-grade-tab/get k] ] which works for all of the above cases. However, if I need to provide a more orderly report, I'll probably write something like foreach k sort/compare age-grade-tab/keys age-grade-sorter [ ; with some nice layout tricks not relevant to this point ] If there is simply a range expansion (grades 1-12 instead of 1-6, with ages 4-18 instead of 6-11) the above code still works (ignoring layout issues). If we go to the mixed coding of (2) above, all I have to do is go to one function age-grade-sorter and adjust it appropriately. All of the rest of the code still works. I VERY much like the idea of encapsulating each policy decision in exactly one place in the code. The idea of having to transform data back and forth between a natural representation and an agglomerated string throughout my program (just because some language feature has a bias in favor of strings) strikes me as very ugly, as well as a fruitful source of coding and maintenance errors. I could make up more examples, but I hope the single one above is adequate to explain the "flavor" of the concept without more belaboring.
> It seems like an implementation would be easier and/or more efficient if we > didn't have to worry about that case. Same for logic! values :) >
What worry? REBOL already knows how to take two values and compare them for equality. The block! and logic! types just happen to be two examples of that more general principle. What if I wanted to tally up the birthdates of the students? Isn't it meaningful to use a date! key for a count of how many students had a birthday on that date? REBOL already can do that, and equality comparison on date! values is much more complex that testing logic! values for equality.
> Many other languages get by with just strings for keys, ... >
Many other languages "get by" without MOST of the nicer features of REBOL. If all I wanted was a language which could "get by", I'd keep writing in C. REBOL has been presented as a high-level language which can do make use of a wide range of user-friendly data types. I think it is unfriendly to have arbitrary restrictions on which of them can be used in some situations.
> ...why do we have to be able to use every Rebol data type as a key? >
Anyone who wants to use only strings as keys, and can get his/her work done effectively under that restriction has my blessing. I'm not trying to force anyone to use any feature they don't see a need for. On the other hand, I'll be sad if the hypothetical person in the previous paragraph tells me that I CAN'T use any other type of key, even when I can see good reason to do so in my own code. -jn-

 [37/41] from: al:bri:xtra at: 19-Sep-2000 19:36


This is a multi-part message in MIME format. ------=_NextPart_000_02E4_01C02270.F44DE100 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit Here's another version of %Associate.r that should cope with the tests that Ladislav and Joel have thrown at it. I haven't yet worked out how to fix Ladislav's concern yet:
> The other problem is, that your functions won't accept Any-type! values
for Key/Value Comments and criticism gratefully accepted. I'm sure that my wrapper around 'Find can be done better, too. [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 19/September/2000 ] Associate!: make object! [ Find: function [Block [block!] Key] [Index] [ Index: Block until [ Index: system/words/find/only Index Key if not found? Index [return none] either odd? offset? Block Index [ Index: next Index false ][ true ] ] Index ] set 'Associate? function [Block [block!] Key] [Index] [ either found? Index: Find Block Key [ first second Index ][ none ] ] set 'Associate function [Block [block!] Key Value] [Index] [ Index: Find Block Key either none? Value [ if found? Index [ remove/part Index 2 ] ][ Value: reduce [Value] either found? Index [ change/only next Index Value ][ append Block reduce [Key Value] ] ] Block ] ] ]
>> do %associate.r >> blk: []
== []
>> Associate blk [2 3] 5
== [[2 3] [5]]
>> Associate? blk [2 3]
== 5
>> Associate blk 5 7
== [[2 3] [5] 5 [7]]
>> Associate blk [5] 9
== [[2 3] [5] 5 [7] [5] [9]]
>> Associate? blk 5
== 7
>> Associate? blk [5]
== 9
>> Associate? blk reduce [2 3]
== 5
>> Associate? blk reduce [[2 3]]
== none
>> Associate? blk reduce [[5]]
== none
>> blk: copy []
== []
>> associate blk [2] 3
== [[2] [3]]
>> associate? blk [2]
== 3 Andrew Martin Nietzchean Rebolutionary... ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_02E4_01C02270.F44DE100 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 19/September/2000 ] Associate!: make object! [ Find: function [Block [block!] Key] [Index] [ Index: Block until [ Index: system/words/find/only Index Key if not found? Index [return none] either odd? offset? Block Index [ Index: next Index false ][ true ] ] Index ] set 'Associate? function [Block [block!] Key] [Index] [ either found? Index: Find Block Key [ first second Index ][ none ] ] set 'Associate function [Block [block!] Key Value] [Index] [ Index: Find Block Key either none? Value [ if found? Index [ remove/part Index 2 ] ][ Value: reduce [Value] either found? Index [ change/only next Index Value ][ append Block reduce [Key Value] ] ] Block ] ] ] ------=_NextPart_000_02E4_01C02270.F44DE100--

 [38/41] from: al:bri:xtra at: 19-Sep-2000 21:40


> It would be very pleasant, IMHO, to be able to write something like the
following sketch:
> age-grade-tab/put a-g 1 + any [age-grade-tab/get a-g 0]
Will this do? Associate age-grade-tab a-g 1 + any [associate? age-grade-tab a-g 0]
> foreach k age-grade-tab/keys [ > print [k ":" age-grade-tab/get k] > ]
How about this? use [Keys] [ Keys: age-grade-tab forskip 'Keys 2 [ print [first Keys ":" Associate? Keys] ] ]
> foreach k sort/compare age-grade-tab/keys age-grade-sorter [ > ; with some nice layout tricks not relevant to this point > ]
foreach [Key Value] sort/compare/skip age-grade-tab age-grade-sorter 2 [ I hope that helps! Andrew Martin find/skip select/skip... ICQ: 26227169 http://members.ncbi.com/AndrewMartin/ http://members.xoom.com/AndrewMartin/

 [39/41] from: joel:neely:fedex at: 19-Sep-2000 8:35


Hi, Andrew! [Al--Bri--xtra--co--nz] wrote:
> > It would be very pleasant, IMHO, to be able to write something like the > following sketch:
<<quoted lines omitted: 15>>
> > ] > foreach [Key Value] sort/compare/skip age-grade-tab age-grade-sorter 2 [
Of course! Thank you! 1) The motivation for my original note on the age/grade example was specifically to explain why I believe there are reasonable uses for block! data as keys. If memory serves, your Associate and Associate? functions support that capability. So I think we're in violent agreement here ;-) since we're dealing with the same concept. 2) The main difference between our proposals is whether to use a collection of functions or an object-oriented approach. That discussion gets us into deeper waters. I tend to use objects wherever possible for a bunch of reasons: 2.1) I like to keep as much as possible out of the global namespace. This reduces my risk of name collision when reusing code. 2.2) I like having the data structure definition in the same physical source file (always!) as the algorithms that work with/on it. This reduces my risk of inadvertent changes or incon- sistency when applying functions to independently-built data structures. 2.3) I like being able to define the required behavior of an object, and (once I've implemented it) think of the object ONLY in terms of the interface to invoke those behaviors. This reduces my risk of breaking code that uses the object if I later figure out a better implementation and change the "insides" of the function. I'll stop with those three, but hope that I've laid the basis for the real issue -- I think it makes sense to look at programming from a cost/benefit analysis perspective. The reduction of risk issues I raised above are benefits (to me, at least -- YMMV) The cost of using objects (in ANY language) typically includes a bit of overhead due to additional indirection in accessing the components of the object. The cost of using objects in REBOL (at least at THIS point in time) incudes the fact that everything in an object is cloned when it is used as a template for creating another object. For most of my purposes, those costs are not high enough to outweigh the benefits; I certainly have no quarrel with anyone whose evaluation of the tradeoff differs. (It does sadden me when these differences are either ignored or used as the basis of holy wars, however.) The bottom line is that I'd prefer a language that gives me as general and wide-ranging set of concepts as possible, and leaves the tradeoff decisions to me (on a case-by-case basis, even). I think that's much better, in general, than having such choices made in advance by the language (concept, notation, or implemen- tation) and set in concrete. -jn-

 [40/41] from: brian:hawley:bigfoot at: 19-Sep-2000 22:57


Joel Neely wrote:
>1) The motivation for my original note on the age/grade example was > specifically to explain why I believe there are reasonable uses >for block! data as keys. If memory serves, your Associate and > Associate? functions support that capability. So I think we're in >violent agreement here ;-) since we're dealing with the same >concept.
There are only two problems with using blocks as keys. First, blocks can be recursive, directly or indirectly. You can't directly compare recursive blocks without crashing REBOL. This is true not only for the equality operations but also for find and select as well. I just checked every comparison operator - you can't even use =? or <>. Second, the hash! type only hashes on string types. There is no reason to expect RT to extend hashing to block types - the most we could hope for would be immediate values and word types. To hash structured values is an expensive process. Both these problems are solved by molding any-block! keys. Mold now works on recursive structures, and the result is a string. It even allows hashes to optimize lookup of non-strings. This is only speed-efficient with large amounts of data but at least it won't crash REBOL. I'll stay neutral on the cost/benefit analysis of objects versus global functions. I chalk it up to individual preference. Brian Hawley

 [41/41] from: al:bri:xtra at: 21-Sep-2000 6:17


This is a multi-part message in MIME format. ------=_NextPart_000_00BD_01C02393.AAD19340 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 7bit jn wrote:
> The main difference between our proposals is whether to use a collection
of functions or an object-oriented approach. That discussion gets us into deeper waters. In the spirit of putting oil on waters, here's Association.r which allows the use of objects as well as functions for an Associative Data Store: [ Rebol [ Title: "Association" Name: 'Association File: %Association.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 21/September/2000 ] do %Associate.r Association!: make object! [ Block: block! Get: func [Key [any-type!]] [ Associate? Block Key ] Set: func [Key [any-type!] Value [any-type!]] [ Associate Block Key Value ] ] Association: func [/Size Value [integer!]] [ all [ not Size Value: 1 ] make Association! [ Block: make block! Value ] ] ]
>> do %Association.r >> A: Association >> probe a
make object! [ Block: [] Get: func [Key [any-type!]][ Associate? Block Key ] Set: func [Key [any-type!] Value [any-type!]][ Associate Block Key Value ] ]
>> a/set [1 2] "hello"
== [[1 2] ["hello"]]
>> a/set [1 5] "1-5"
== [[1 2] ["hello"] [1 5] ["1-5"]]
>> a/get [1 2]
== "hello"
>> a/get [1 5]
== "1-5" Andrew Martin Why sleep when I can write Rebol? ICQ: 26227169 http://members.ncbi.com/andrewmartin/ http://members.xoom.com/AndrewMartin/ -><- ------=_NextPart_000_00BD_01C02393.AAD19340 Content-Type: text/x-rebol; name="Association.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Association.r" [ Rebol [ Title: "Association" Name: 'Association File: %Association.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 21/September/2000 ] do %Associate.r Association!: make object! [ Block: block! Get: func [Key [any-type!]] [ Associate? Block Key ] Set: func [Key [any-type!] Value [any-type!]] [ Associate Block Key Value ] ] Association: func [/Size Value [integer!]] [ all [ not Size Value: 1 ] make Association! [ Block: make block! Value ] ] ] ------=_NextPart_000_00BD_01C02393.AAD19340 Content-Type: text/x-rebol; name="Associate.r" Content-Transfer-Encoding: 7bit Content-Disposition: attachment; filename="Associate.r" [ Rebol [ Title: "Associate" Name: 'Associate File: %Associate.r Author: "Andrew Martin" Email: [Al--Bri--xtra--co--nz] Date: 19/September/2000 ] Associate!: make object! [ Find: function [Block [block!] Key] [Index] [ Index: Block until [ Index: system/words/find/only Index Key if not found? Index [return none] either odd? offset? Block Index [ Index: next Index false ][ true ] ] Index ] set 'Associate? function [Block [block!] Key] [Index] [ either found? Index: Find Block Key [ first second Index ][ none ] ] set 'Associate function [Block [block!] Key Value] [Index] [ Index: Find Block Key either none? Value [ if found? Index [ remove/part Index 2 ] ][ Value: reduce [Value] either found? Index [ change/only next Index Value ][ append Block reduce [Key Value] ] ] Block ] ] ] ------=_NextPart_000_00BD_01C02393.AAD19340--

Notes
  • Quoted lines have been omitted from some messages.
    View the message alone to see the lines that have been omitted