Hashes in Rebol
[1/12] from: knizhnik:garret:ru at: 9-Dec-2003 14:47
Sorry, I am trying to implement Rebol API to my OO database DyBASE and
not yet familiar with Rebol.
I completely confused by lack of normal associative arrays or hashes.
Yes - in Rebol there is hash! type and "select" function makes it
possible to extract values from hash. But I also want to remove and
replace elements in hash. There no hash specific "replace" and "remove" functions
which can deal with <key, value> pairs.
Certainly, I am sure that it is possible to update hash table using
standard "remove" and "replace" function but it seems to be non
trivial. So may be I missed something? Associative arrays are one of
the most fundamental structure especially in scripting language and
some languages provides no other collection types except arrays. Why
them are implemented in Rebol in such strange way?
Once again sorry for question which may be obvious for
experienced Rebol programmers, but how can I
1. Remove <key, value> pair from hash
2. Change value associated with the particular key
--
Best regards,
Konstantin mailto:[knizhnik--garret--ru]
[2/12] from: greggirwin:mindspring at: 9-Dec-2003 8:01
Hi Konstantin,
KK> Why them are implemented in Rebol in such strange way?
I think for consistency with other series types. REBOL's standard path
notation is extremely convenient.
KK> ...how can I
KK> 1. Remove <key, value> pair from hash
KK> 2. Change value associated with the particular key
>> hash: make hash! []
== make hash! []
>> append hash [A 1 B 2 C 3 D 4]
== make hash! [A 1 B 2 C 3 D 4]
>> hash/b
== 2
>> hash/b: 22
== make hash! [A 1 B 22 C 3 D 4]
>> remove/part find hash 'b 2
== make hash! [C 3 D 4]
>> hash
== make hash! [A 1 C 3 D 4]
You can also use intermediate words as variables, along with the
get-word! syntax in the path to evaluate them
>> key: 'c
== c
>> hash/:key
== 3
But you can't set values that way.
>> hash/:key: 33
** Syntax Error: Invalid word -- :key:
** Near: (line 1) hash/:key: 33
You need to do something like the following:
>> head change next find hash key 33
== make hash! [A 1 C 33 D 4]
Or write a little wrapper for that (no error handling in example!):
>> my-replace: func [series key value][change next find series key value]
>> head my-replace hash 'd 44
== make hash! [A 1 C 33 D 44]
Of course, you could make things work how you want, any number of
ways. e.g.
; Keys don't *have* to be strings.
; If you assign a block to _data, it's up to you to make it a hash! if you want.
dictionary: make object! [
; Odd items are keys, even items are values. I.e.
; [key1 value1 key2 value2...]
_data: make hash! []
clear: does [_data: make hash! []]
count: does [(system/words/length? _data) / 2]
length?: :count
empty?: does [count = 0]
keys: does [extract head _data 2]
values: does [extract next head _data 2]
item: func [key] [
if has-key? key [_data/:key]
]
has-key?: func [key] [
found? find/skip _data key 2
]
remove: func [key] [
if has-key? key [system/words/remove/part find/skip _data key 2 2]
]
change: func [key value] [
either has-key? key [_data/:key :value][append _data reduce [key :value]]
]
contains?: func [value /only] [
either only [
found? find/skip/only next _data value 2
][
found? find/skip next _data value 2
]
]
]
;d: make dictionary []
;d/_data: ["A" 1 "B" 2 "C" 3 "D" 4]
;d/change 0.0.0 "black"
;d/item 0.0.0
In your case that might be a good choice, but the main thing to look
at for "normal" REBOL usage is how the model fits with standard REBOL
idioms and style. REBOL is quite different from other languages, and
sometimes trying to make it work like them will look good initially,
because you're making it act in a familiar way. Sometimes, though, it
will lead to inelegant solutions later because you just keep adding
things, rather than stripping them away.
The main thing to remember with REBOL is that everything is just
data--a series of values--until it is evaluated.
HTH!
-- Gregg
[3/12] from: andreas:bolka:gmx at: 9-Dec-2003 15:59
Tuesday, December 9, 2003, 12:47:53 PM, Konstantin wrote:
> Once again sorry for question which may be obvious for experienced
> Rebol programmers, but how can I
> 1. Remove <key, value> pair from hash
remove/part find hash key 2
> 2. Change value associated with the particular key
change find/tail hash key newvalue
--
Best regards,
Andreas
[4/12] from: knizhnik:garret:ru at: 9-Dec-2003 21:56
Hello Andreas,
Tuesday, December 9, 2003, 5:59:27 PM, you wrote:
AB> Tuesday, December 9, 2003, 12:47:53 PM, Konstantin wrote:
>> Once again sorry for question which may be obvious for experienced
>> Rebol programmers, but how can I
>> 1. Remove <key, value> pair from hash
AB> remove/part find hash key 2
>> 2. Change value associated with the particular key
AB> change find/tail hash key newvalue
Thank you very much.
AB> --
AB> Best regards,
AB> Andreas
--
Best regards,
Konstantin mailto:[knizhnik--garret--ru]
[5/12] from: knizhnik:garret:ru at: 9-Dec-2003 22:03
Hello Gregg,
Thank you very much for explanation.
Certainly it is very universal approach to treat everything as
series. But as all universal solutions is is not always convenient to
use:). If I remove exactly one element from the hash - what will be
result of such operation...
But actually I need hash table with integer key (object OID).
And here once again Rebol rules are not compatible with my
expectations:
== make hash! [1 "one" 2 "two"]
>> h select 1
** Script Error: select expected series argument of type: series port
Is it possible to have hash table with integer key?
Or I should first convert it to string?
Tuesday, December 9, 2003, 6:01:44 PM, you wrote:
GI> Hi Konstantin,
KK>> Why them are implemented in Rebol in such strange way?
GI> I think for consistency with other series types. REBOL's standard path
GI> notation is extremely convenient.
KK>> ...how can I
KK>> 1. Remove <key, value> pair from hash
KK>> 2. Change value associated with the particular key
>>> hash: make hash! []
GI> == make hash! []
>>> append hash [A 1 B 2 C 3 D 4]
GI> == make hash! [A 1 B 2 C 3 D 4]
>>> hash/b
GI> == 2
>>> hash/b: 22
GI> == make hash! [A 1 B 22 C 3 D 4]
>>> remove/part find hash 'b 2
GI> == make hash! [C 3 D 4]
>>> hash
GI> == make hash! [A 1 C 3 D 4]
GI> You can also use intermediate words as variables, along with the
GI> get-word! syntax in the path to evaluate them
>>> key: 'c
GI> == c
>>> hash/:key
GI> == 3
GI> But you can't set values that way.
>>> hash/:key: 33
GI> ** Syntax Error: Invalid word -- :key:
GI> ** Near: (line 1) hash/:key: 33
GI> You need to do something like the following:
>>> head change next find hash key 33
GI> == make hash! [A 1 C 33 D 4]
GI> Or write a little wrapper for that (no error handling in example!):
>>> my-replace: func [series key value][change next find series key value]
>>> head my-replace hash 'd 44
GI> == make hash! [A 1 C 33 D 44]
GI> Of course, you could make things work how you want, any number of
GI> ways. e.g.
GI> ; Keys don't *have* to be strings.
GI> ; If you assign a block to _data, it's up to you to make it a hash! if you want.
GI> dictionary: make object! [
GI> ; Odd items are keys, even items are values. I.e.
GI> ; [key1 value1 key2 value2...]
GI> _data: make hash! []
GI> clear: does [_data: make hash! []]
GI> count: does [(system/words/length? _data) / 2]
GI> length?: :count
GI> empty?: does [count = 0]
GI> keys: does [extract head _data 2]
GI> values: does [extract next head _data 2]
GI> item: func [key] [
GI> if has-key? key [_data/:key]
GI> ]
GI> has-key?: func [key] [
GI> found? find/skip _data key 2
GI> ]
GI> remove: func [key] [
GI> if has-key? key [system/words/remove/part find/skip _data key 2 2]
GI> ]
GI> change: func [key value] [
GI> either has-key? key [_data/:key :value][append _data reduce [key :value]]
GI> ]
GI> contains?: func [value /only] [
GI> either only [
GI> found? find/skip/only next _data value 2
GI> ][
GI> found? find/skip next _data value 2
GI> ]
GI> ]
GI> ]
GI> ;d: make dictionary []
GI> ;d/_data: ["A" 1 "B" 2 "C" 3 "D" 4]
GI> ;d/change 0.0.0 "black"
GI> ;d/item 0.0.0
GI> In your case that might be a good choice, but the main thing to look
GI> at for "normal" REBOL usage is how the model fits with standard REBOL
GI> idioms and style. REBOL is quite different from other languages, and
GI> sometimes trying to make it work like them will look good initially,
GI> because you're making it act in a familiar way. Sometimes, though, it
GI> will lead to inelegant solutions later because you just keep adding
GI> things, rather than stripping them away.
GI> The main thing to remember with REBOL is that everything is just
GI> data--a series of values--until it is evaluated.
GI> HTH!
GI> -- Gregg
--
Best regards,
Konstantin mailto:[knizhnik--garret--ru]
[6/12] from: chris:langreiter at: 9-Dec-2003 20:33
> == make hash! [1 "one" 2 "two"]
>>> h select 1
select h 1
[7/12] from: ingo:2b1 at: 9-Dec-2003 20:51
Hi Konstantin,
I guess you suffer from too much object oriented programming ;-)
>> h: make hash! [3 "three" 1 "one" 2 "two" ]
== make hash! [3 "three" 1 "one" 2 "two"]
>> select h 1
== "one"
(pay especially close attention to the order in which select, h, and 1
stay on this line ... )
And btw, please do ask all the questions you have, it's not uncommon for
even seasoned Rebolers to find something new in the answers to seemeingly
easy questions (as just happened to me with the usage of find/tail)
Kind regards,
Ingo
Konstantin Knizhnik wrote:
[8/12] from: knizhnik:garret:ru at: 9-Dec-2003 22:57
Hello Christian,
Tuesday, December 9, 2003, 10:33:44 PM, you wrote:
>> == make hash! [1 "one" 2 "two"]
>>>> h select 1
CL> select h 1
O, sorry - such stupid mistyping:(
I was confused, because
h select "1"
doesn't report any error and returns none...
--
Best regards,
Konstantin mailto:[knizhnik--garret--ru]
[9/12] from: nitsch-lists::netcologne::de at: 9-Dec-2003 20:56
Am Dienstag 09 Dezember 2003 20:03 schrieb Konstantin Knizhnik:
> Hello Gregg,
> Thank you very much for explanation.
<<quoted lines omitted: 10>>
> Is it possible to have hash table with integer key?
> Or I should first convert it to string?
Better convert it to this syntax:
>> h: make hash! [1 "one" 2 "two"]
== make hash! [1 "one" 2 "two"]
>> select h 1
== "one"
;)
method object
in rebol for inbuilds.
-Volker
[10/12] from: nitsch-lists:netcologne at: 9-Dec-2003 21:09
Am Dienstag 09 Dezember 2003 15:59 schrieb Andreas Bolka:
> Tuesday, December 9, 2003, 12:47:53 PM, Konstantin wrote:
> > Once again sorry for question which may be obvious for experienced
<<quoted lines omitted: 4>>
> > 2. Change value associated with the particular key
> change find/tail hash key newvalue
some notes when used to "usual" hash-tables:
1) there is /skip for find and such. If you have the same type for key and
data, that helps. then:
find/skip block key 2
instead of
find block key
with different types it does not matter, because 'fid is type-sensitive.
2) use /only when adding blocks to blocks. append/only, change/only.
>> append to-hash[1 2 3] [4 5] ; wrong
== make hash! [1 2 3 4 5]
>> append/only to-hash[1 2 3] [4 5] ;right
== make hash! [1 2 3 [4 5]]
3), when changing/adding items first check if they are pesent. in other
languages old keys are overwritten, rebol wants a user-check.
;to add something
either pos: find/tail hash key [
change/only pos value
] [
repend hash [key value] ; = append hash reduce[key value]
]
-Volker
[11/12] from: the:optimizer:tiscali:it at: 9-Dec-2003 21:16
On Tue, 9 Dec 2003 22:03:52 +0300, Konstantin Knizhnik <[knizhnik--garret--ru]>
wrote:
> But actually I need hash table with integer key (object OID).
> And here once again Rebol rules are not compatible with my
<<quoted lines omitted: 4>>
> Is it possible to have hash table with integer key?
> Or I should first convert it to string?
Not a big expert but you MAY TRY:
>> h: make hash! [1 "one" 2 "two"]
== make hash! [1 "one" 2 "two"]
select h 1
== "one"
>> select h 2
== "two"
Is this what you wanted?
M&F
[12/12] from: nitsch-lists:netcologne at: 9-Dec-2003 21:37
Am Dienstag 09 Dezember 2003 20:57 schrieb Konstantin Knizhnik:
> Hello Christian,
> Tuesday, December 9, 2003, 10:33:44 PM, you wrote:
<<quoted lines omitted: 6>>
> h select "1"
> doesn't report any error and returns none...
eeks. yes,
ARGUMENTS:
series -- (Type: series port)
value -- (Type: any-type)
that means any-type, including nothing. like this:
> a: reduce[1 "one" () "what??"]
!== [1 "one" unset "what??"]
>> (select a)
!== "what??"
if it does not find unset, it returns none. like your error:
>> (select [1 2])
== none
has some uses in console. for example 'help can be called with or without a
word.
with 'select its quite confusing.
-Volker
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted