[REBOL] Associative Data Store Re:(6)

2000-09-20 Thread Al . Bri

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: [EMAIL PROTECTED]
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/
--



[
Rebol [
	Title: "Association"
	Name: 'Association
	File: %Association.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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
		]
	]

]


[
Rebol [
	Title: "Associate"
	Name: 'Associate
	File: %Associate.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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
		]
	]

]



[REBOL] Associative Data Store Re:(2)

2000-09-19 Thread Al . Bri

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: [EMAIL PROTECTED]
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/
--



[
Rebol [
	Title: "Associate"
	Name: 'Associate
	File: %Associate.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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
		]
	]

]



[REBOL] Associative Data Store Re:(4)

2000-09-19 Thread Al . Bri

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





[REBOL] Associative Data Store Re:(5)

2000-09-19 Thread joel . neely

Hi, Andrew!

[EMAIL PROTECTED] wrote:
 
  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 [
 

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-




[REBOL] Associative Data Store Re:(6)

2000-09-19 Thread brian . hawley

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




[REBOL] Associative Data Store Re:

2000-09-18 Thread joel . neely

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-

[EMAIL PROTECTED] 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]




[REBOL] Associative Data Store Re:

2000-09-18 Thread lmecir

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

 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: [EMAIL PROTECTED]
 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/
 --






[REBOL] Associative Data Store Re:(2)

2000-09-18 Thread rebol

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

- Original Message -
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Sent: Monday, September 18, 2000 7:47 AM
Subject: [REBOL] Associative Data Store Re:


 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-

 [EMAIL PROTECTED] 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]





[REBOL] Associative Data Store Re:(3)

2000-09-18 Thread petr . krenzelok


- Original Message -
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
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-


 Keith

 - Original Message -
 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Monday, September 18, 2000 7:47 AM
 Subject: [REBOL] Associative Data Store Re:


  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-
 
  [EMAIL PROTECTED] 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]





[REBOL] Associative Data Store Re:(4)

2000-09-18 Thread ryanc

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

[EMAIL PROTECTED] wrote:

 - Original Message -
 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 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-

 
  Keith
 
  - Original Message -
  From: [EMAIL PROTECTED]
  To: [EMAIL PROTECTED]
  Sent: Monday, September 18, 2000 7:47 AM
  Subject: [REBOL] Associative Data Store Re:
 
 
   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-
  
   [EMAIL PROTECTED] 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]
 

--


 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





[REBOL] Associative Data Store Re:(5)

2000-09-18 Thread ryanc

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

[EMAIL PROTECTED] wrote:

 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

 [EMAIL PROTECTED] wrote:

  - Original Message -
  From: [EMAIL PROTECTED]
  To: [EMAIL PROTECTED]
  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-
 
  
   Keith
  
   - Original Message -
   From: [EMAIL PROTECTED]
   To: [EMAIL PROTECTED]
   Sent: Monday, September 18, 2000 7:47 AM
   Subject: [REBOL] Associative Data Store Re:
  
  
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-
   
[EMAIL PROTECTED] 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]
  

 --

  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




[REBOL] Associative Data Store Re:(3)

2000-09-18 Thread joel . neely

[EMAIL PROTECTED] 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) 

[REBOL] Associative data store Re:(3)

2000-09-17 Thread Al . Bri

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




[REBOL] Associative data store Re:(5)

2000-09-17 Thread Al . Bri

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] [
   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]
 ]

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





[REBOL] Associative data store Re:

2000-09-15 Thread Al . Bri

I wanted to use integers as keys, so I wrote this up.

[
Rebol [
Title: "Associate"
Name: 'Associate
File: %Associate.r
Author: "Andrew Martin"
Email: [EMAIL PROTECTED]
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/
--



[
Rebol [
	Title: "Associate"
	Name: 'Associate
	File: %Associate.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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]
	]

]



[REBOL] Associative data store Re:(2)

2000-09-15 Thread Al . Bri

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: [EMAIL PROTECTED]
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/
--


[
Rebol [
	Title: "Associate"
	Name: 'Associate
	File: %Associate.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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]
	]

]



[REBOL] Associative data store Re:(5)

2000-09-15 Thread ryanc

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.

[EMAIL PROTECTED] 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.

 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

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





[REBOL] Associative data store Re:(4)

2000-09-15 Thread joel . neely

[EMAIL PROTECTED] 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-




[REBOL] Associative data store Re:(3)

2000-09-15 Thread Al . Bri

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: [EMAIL PROTECTED]
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/
--



[
Rebol [
	Title: "Associate"
	Name: 'Associate
	File: %Associate.r
	Author: "Andrew Martin"
	Email: [EMAIL PROTECTED]
	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]
	]

]



[REBOL] Associative data store Re:

2000-09-14 Thread bobr

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, [EMAIL PROTECTED] 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: [EMAIL PROTECTED]




[REBOL] Associative data store Re:(2)

2000-09-14 Thread rebol

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?

- Original Message -
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Sent: Thursday, September 14, 2000 1:07 PM
Subject: [REBOL] Associative data store Re:


 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, [EMAIL PROTECTED] 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: [EMAIL PROTECTED]




[REBOL] Associative data store Re:(2)

2000-09-14 Thread joel . neely

Silly me!  Thanks for catching the oversight.

[EMAIL PROTECTED] 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  [EMAIL PROTECTED]  901-263-4460  38017/HKA/9677
REBOL []  print to-string debase/64 decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C2400}




[REBOL] Associative data store Re:(3)

2000-09-14 Thread joel . neely

[EMAIL PROTECTED] 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  [EMAIL PROTECTED]  901-263-4460  38017/HKA/9677
REBOL []  print to-string debase/64 decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C2400}




[REBOL] Associative data store Re:

2000-09-14 Thread rebol

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-"]
== true
 assoc-add phonelist [Al "555-"]
== true
 assoc-add phonelist [George "555-"]
== true
 assoc-add phonelist [Dick "555-"]
== true
 assoc-add phonelist [Jane "555-3322" Judy "555-2233"]
== true
 assoc-get phonelist 'Bill
== "555-"
 assoc-get phonelist 'Dick
== "555-"
 assoc-get phonelist 'George
== "555-"
 assoc-get phonelist 'Jane
== "555-3322"
 assoc-get phonelist 'Judy
== "555-2233"
 assoc-get phonelist 'Al
== "555-"

 foreach who sort copy phonelist/keys [print [who assoc-get phonelist who]]
Al 555-
Bill 555-
Dick 555-
George 555-
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
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-"
== "555-"
 phonelist/put "Al" "555-"
== "555-"
 phonelist/put "George" "555-"
== "555-"
 phonelist/put "Dick" "555-"
== "555-"
 phonelist/get "Al"
== "555-"
 phonelist/count?
== 4
 phonelist/keys
== ["Bill" "Al" "George" "Dick"]
 foreach who phonelist/keys [print [who "^-" phonelist/get who]]
Bill 555-
Al   555-
George   555-
Dick 555-
 foreach who sort phonelist/keys [print [who "^-" phonelist/get who]]
Al   555-
Bill 555-
Dick 555-
George   555-
 privatelist: phonelist/new
 privatelist/count?
== 0

 foreach who head reverse sort phonelist/keys [
[print [who "^-" phonelist/get who]
[]
George   555-
Dick 555-
Bill 555-
Al   555-
==(end transcript)===

Enjoy!

-jn-

-- 
; Joel Neely  [EMAIL PROTECTED]  901-263-4460  38017/HKA/9677
REBOL []  print to-string debase/64 decompress #{
789C0BCE0BAB4A7176CA48CAB53448740FABF474F3720BCC
B6F4F574CFC888342AC949CE74B50500E1710C0C2400}




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





[REBOL] Associative data store Re:(2)

2000-09-14 Thread rsnell

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



-Original Message-
From: [EMAIL PROTECTED] [mailto:[EMAIL PROTECTED]]
Sent: Thursday, September 14, 2000 1:38 PM
To: [EMAIL PROTECTED]
Subject: [REBOL] Associative data store Re:


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-"]
== true
 assoc-add phonelist [Al "555-"]
== true
 assoc-add phonelist [George "555-"]
== true
 assoc-add phonelist [Dick "555-"]
== true
 assoc-add phonelist [Jane "555-3322" Judy "555-2233"]
== true
 assoc-get phonelist 'Bill
== "555-"
 assoc-get phonelist 'Dick
== "555-"
 assoc-get phonelist 'George
== "555-"
 assoc-get phonelist 'Jane
== "555-3322"
 assoc-get phonelist 'Judy
== "555-2233"
 assoc-get phonelist 'Al
== "555-"

 foreach who sort copy phonelist/keys [print [who assoc-get phonelist
who]]
Al 555-
Bill 555-
Dick 555-
George 555-
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
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-"
== "555-"
 phonelist/put "Al" "555-"
== "555-"
 phonelist/put "George" "555-"
== "555-"
 phonelist/put "Dick" "555-"
== "555-"
 phonelist/get "Al"
== "555-"
 phonelist/count?
== 4
 phonelist/keys
== ["Bill" "Al" "George" "Dick"]
 foreach who phonelist/keys [print [who "^-" phonelist/get who]]
Bill 555-
Al   555-
George   555-
Dick 555-
 fore

[REBOL] Associative data store Re:(2)

2000-09-14 Thread rebol

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
insert assoc/values value
  ]
]
return true
  ]
  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





[REBOL] Associative data store Re:(4)

2000-09-14 Thread allen

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



REBOL [
Title: "Collection Object"
Author: "Allen Kamp"
Date: 11-Sep-1999
Email: [EMAIL PROTECTED] 
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
]  
]
   ]
] 


[REBOL] Associative data store Re:(4)

2000-09-14 Thread ryanc

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





[REBOL] Associative data store Re:(3)

2000-09-14 Thread rebol

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

- Original Message -
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Sent: Thursday, September 14, 2000 5:57 PM
Subject: [REBOL] Associative data store Re:(2)


 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
 insert assoc/values value
   ]
 ]
 return true
   ]
   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






[REBOL] Associative data store Re:(4)

2000-09-14 Thread ryanc

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"]


[EMAIL PROTECTED] wrote:

 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

 - Original Message -
 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Thursday, September 14, 2000 5:57 PM
 Subject: [REBOL] Associative data store Re:(2)

  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
  insert assoc/values value
]
  ]
  return true
]
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
 

--


 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





[REBOL] Associative data store Re:(4)

2000-09-14 Thread rebol

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?

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

- Original Message -
From: [EMAIL PROTECTED]
To: [EMAIL PROTECTED]
Sent: Thursday, September 14, 2000 5:57 PM
Subject: [REBOL] Associative data store Re:(2)


 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
 insert assoc/values value
   ]
 ]
 return true
   ]
   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






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





[REBOL] Associative data store Re:(4)

2000-09-14 Thread agem




[EMAIL PROTECTED] 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?
 
 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
 
 - Original Message -
 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Thursday, September 14, 2000 5:57 PM
 Subject: [REBOL] Associative data store Re:(2)
 
 
  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
  insert assoc/values value
]
  ]
  return true
]
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
 
 
 
 
 




[REBOL] Associative data store Re:(4)

2000-09-14 Thread agem



[EMAIL PROTECTED] 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"
 
 (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"


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

 
 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
 
 - Original Message -
 From: [EMAIL PROTECTED]
 To: [EMAIL PROTECTED]
 Sent: Thursday, September 14, 2000 5:57 PM
 Subject: [REBOL] Associative data store Re:(2)
 
 
  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
  insert assoc/values value
]
  ]
  return true
]
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