The all function.
[1/18] from: louisaturk:eudoramail at: 12-Apr-2002 14:43
Rebol friends,
I have the following line of code to check to make sure that a record does
not already exist, but it always returns none:
rec: all [find database code find database chknum]
>> find database code
== make hash! ["boo"
make object! [
code: "boo"
chknum: "9898"
date: 19-Jan-2001
amount: $100....
>> find database 2 chknum
== "9898"
>> rec: all [find database code find database 2 chknum]
== none ; Why is this none????????????????
Futher testing shows where the failure is happening:
>> rec: all [find database code]
== make hash! ["boo"
make object! [
code: "boo"
chknum: "9898"
date: 19-Jan-2001
amount: $100....
>> rec: all [find database 2 chknum]
== none
>> find database 2 chknum
== "9898"
>> all [find database 2 chknum]
== none
>> find database 2 chknum
== "9898"
>>
Why?
Louis
[2/18] from: louisaturk:eudoramail at: 12-Apr-2002 20:56
I found the solution---add the word copy.
rec: all [find database code copy (find database chknum)]
For some reason I keep having to learn that lesson again and again. :>)
Louis
At 02:43 PM 4/12/2002 -0500, you wrote:
[3/18] from: anton:lexicon at: 13-Apr-2002 15:42
No, adding copy didn't fix your code.
Removing the 2 did. (Although, I am not really
sure it is fixed...)
The problem is that find takes two arguments,
not three, as you seem to think in this line:
find database 2 chknum
This just returns the value of chknum.
You had obviously set chknum sometime in your testing
on the console. I'll put brackets to show how the
above line was evaluated:
(find database 2) (chknum)
The first value returns none, the second value returns
9898
, which must have been what you set it to at
some point.
In the 'all block, you actually had three values to
check, not two, as I am sure you thought you had:
rec: all [find database code find database 2 chknum]
I will put brackets to show how it was evaluated.
rec: all [(find database code) (find database 2) chknum]
So 'all would have returned at the second value (none).
Perhaps you meant to write:
find database/2 chknum
That means to look in the second value of the hash!
Anton.
[4/18] from: louisaturk:eudoramail at: 13-Apr-2002 1:54
Anton,
Thanks for the help. Further testing proved that you are right about my
code being incorrect. However, when I try
find database/2 chknum
I get the following error message:
Code: boo
Check#: 9898
** Script Error: find expected series argument of type: series port bit
set
** Where: forever
** Near: rec: all [find database code find database/2 chknum]
either rec
>>
Here is the the code from my program:
if choice = #"1" [
forever [
print cls
print " ADD A RECORD"
print " ============^/"
code: ask " Code: "
chknum: ask " Check#: "
if code = "" [break] ;gsj added to avoid empty error
rec: all [find database code find database/2
chknum]
either rec = none [
date: ask " Date: "
amount: ask " Amount: "
special: ask " Special Offering: "
insert-data code chknum date amount special
save-data
][
ask "^/ Record is already in database. Continue? "
]
] ; End forever loop for choice 1
] ; End if choice 1
Thanks again,
Louis
At 03:42 PM 4/13/2002 +1000, you wrote:
[5/18] from: inetw3:mindspring at: 13-Apr-2002 19:18
Hello Dr. Louis,
Im still learning how to Rebol my way around, so hopefully someone can
correct me if Im wrong but,
is code & chknum looking for type? string "9898" "BOO"
or type? string and type? number "BOO" 9898
some functions will find string code the first time but afterward
you must specify them with {"BOO"} brackets in order not to
loose your #" " characters.
[6/18] from: anton:lexicon at: 14-Apr-2002 14:05
Sorry, my slip up there. You can't use find on an object!
You should probably use this:
in database/2 'chknum ; to see if there is such a word
database/2/chknum ; get the value (not none or false it's ok).
so...
all [find database code (in database/2 'chknum) database/2/chknum]
[7/18] from: louisaturk:eudoramail at: 13-Apr-2002 23:45
Hi,
At 07:18 PM 4/13/2002 -0500, you wrote:
>Hello Dr. Louis,
>
>Im still learning how to Rebol my way around, so hopefully someone can
>correct me if Im wrong but,
>
>is code & chknum looking for type? string "9898" "BOO"
>or type? string and type? number "BOO" 9898
They are both strings.
>some functions will find string code the first time but afterward
>you must specify them with {"BOO"} brackets in order not to
>loose your #" " characters.
I don't understand what you mean. Please give an example.
Louis
[8/18] from: louisaturk:eudoramail at: 14-Apr-2002 0:05
Hi Anton,
Thanks again. But it is still not working. No matter what record I
search for
all [find database code (in database/2 'chknum) database/2/chknum]
appears to be stopping most of the time at the first record in the
database, and returning its chknum.
Louis
At 02:05 PM 4/14/2002 +1000, you wrote:
[9/18] from: anton:lexicon at: 14-Apr-2002 17:33
Now I see your intention.. Golly.
Of course, database/2 always refers to the second
element in your database, which was your first record.
Duh. My apologies for misleading you there.
Ok, what you need is something simple like this:
rec: select database code
select finds the code, then returns the next object.
Great!
Now you can see if rec contains 'chknum and get its value.
chknum: all [(in rec 'chknum) rec/chknum]
Anton.
[10/18] from: joel:neely:fedex at: 14-Apr-2002 7:42
Hi, Louis,
I've had a hard time understanding the exact setting of the
problem... Sorry!
Dr. Louis A. Turk
wrote:
> all [find database code (in database/2 'chknum) database/2/chknum]
>
> appears to be stopping most of the time at the first record in the
> database, and returning its chknum.
>
Let me make a couple of assumptions:
1) DATABASE is a series containing alternating strings (used
as keys) and objects (the corresponding values).
2) Each object has a CHKNUM attribute.
3) Given a key (string) you want the corresponding CHKNUM
value.
I can build a trivial test case for requirements (1) and (2) by
database: []
repeat i 10 [
append database join "X" i
append database make object! [
chknum: i
stuff: random 1000000
]
]
== ["X1"
make object! [
chknum: 1
stuff: 170632
] "X2"
make object! [
chknum: 2
stuff...
Under those assumptions...
rec: all [obref: select database code obref/chknum]
will give you back the CHKNUM field of the object associated
with CODE, or NONE if there is no such key.
>> rec: all [obref: select database "X7" obref/chknum]
== 7
>> rec: all [obref: select database "XYZ" obref/chknum]
== none
>> rec: all [obref: select database "X3" obref/chknum]
== 3
If the phrase
obref: select database code
finds the desired key, then OBREF will refer to the corresponding
object and
obref/chknum
will obtain the desired attribute.
OTOH, if the key does not exist in the series, then OBREF will
be NONE and the ALL will terminate with that value.
Hope I haven't missed the point!
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[11/18] from: louisaturk::eudoramail::com at: 14-Apr-2002 21:00
Anton and Joel,
How thankful I am for you and the others on this list. You all have saved
me so much time. And, frankly, I probably wouldn't be able to get past
problems like this without you.
From studying what both of you have said, I think that the root problem
may be that I have a basic design flaw in my database. This is (I think)
what has confused me, and also is perhaps what has made it difficult for
you to understand my problem. I think I only have one key but need two
keys. (Or maybe I don't need any keys at all! Is only one key per record
allowed?)
Here are the first few records from the database:
>> probe database
make hash! ["bbi"
make object! [
code: "bbi"
chknum: "298"
date: 26-Jan-2001
amount: $40.00
special: $0.00
] "bbi"
make object! [
code: "bbi"
chknum: "315"
date: 9-Feb-2001
amount: $40.00
special: $0.00
] "boo"
make object! [
code: "boo"
chknum: "9898"
date: 19-Jan-2001
amount: $100.00
special: $0.00
] "boo"
make object! [
code: "boo"
chknum: ""
date: 20-Apr-2001
amount: $100.00
special: $0.00
] "bho"
make object! [
code: "bho"
chknum: "5259"
date: 27-Jul-2001
amount: $100.00
special: $0.00
What I am wanting to do is to make sure that the record is not already in
the database before I insert it. In other words, no duplicate _records_
are allowed. Note, however, that although the records are all unique, the
code data is not necessarily unique, nor is the chknum data. There may be
many records with the same code, and also many records with the same
chknum. Only the code / chknum combination is unique.
So, do I perhaps need the records to look like this?:
] "bho" "5259" ; <===<<< TWO KEYS.
make object! [
code: "bho"
chknum: "5259"
date: 27-Jul-2001
amount: $100.00
special: $0.00
Would not this line then return none if the unique record does not exist,
and return the chknum otherswise?:
all [find database code find database chknum]
Am I correct about all this? If so, won't the following functions have to
be rewritten?:
load-data: has [data] [
if exists? db-file [
data: reduce load/all db-file
clear database
if data [
foreach item data [
item: make record item
repend database [item/code item] ;item/key_field item
]
]
database: make hash! database
]
]
update-key-data: func [code-old code-new /local record] [
record: find database code-old
if none? record [alert reform ["Missing record:" code-old] exit]
insert clear first record code-new
]
save-data: has [data] [
data: copy []
foreach [key obj] database [
append/only data obj 5 ; number of fields in each record
]
save db-file data
]
find-data: func [code] [select database code]
remove-data: func [code] [remove/part find database code 2]
insert-data: func [code' chknum' date' amount' special'] [
repend database [
code'
make record [
code: code'
chknum: chknum'
date: date'
amount: amount'
special: special'
]
]
]
These are the functions that Carl wrote for me several years ago for a
database that only had one key. Thanks again Carl! They have served me
well in several databases. This is my first need for two keys.
Thanks again for your help.
Louis
[12/18] from: anton:lexicon at: 15-Apr-2002 14:53
First of all, I have never bothered to use
hash before, so perhaps I will miss some
hash specific details.
As far as I know, hash!s are very similar to blocks.
That means you can put in any number of any
datatype.
There is, due to the key, duplication of data in
the database. The code appears before each
object and within each object. I would try to
eliminate one of them.
I would simplify your hash to a series of
objects only (with the keys in the objects.)
However, that may well not be very speedy.
So you may decide to have two keys then an object,
or store all your keys and data in the objects.
You will need to modify your functions either way.
With your two key example, this line will not work:
all [find database code find database chknum]
It would find code somewhere, then chknum somewhere else,
but who says they are together? Nobody. ;)
Use this instead:
find/skip database reduce [key1 key2] 3
The skip refinement treats the series as records
of fixed number of objects, which is 3 in this case
(2 keys and 1 object).
Anton.
[13/18] from: ingo:2b1 at: 15-Apr-2002 10:40
Hi Louis,
Dr. Louis A. Turk wrote:
<...>
> What I am wanting to do is to make sure that the record is not already
> in the database before I insert it. In other words, no duplicate
<<quoted lines omitted: 11>>
> amount: $100.00
> special: $0.00
well, I think this would get you into much trouble, but how about using
a single key, that joins the two values?, e.g.
>> key: join join code "-" chknum
== "bho-5259"
and then use
] "bho-5259" ; <===<<< ONE KEY, composed of TWO KEYS.
make object! [
code: "bho"
chknum: "5259"
date: 27-Jul-2001
amount: $100.00
special: $0.00
I hope that helps,
Ingo
[14/18] from: louisaturk:eudoramail at: 15-Apr-2002 7:13
Ingo,
This was a great idea, and it seems to have solved my problem!
I changed the load-data function as follows:
load-data: has [data] [
if exists? db-file [
data: reduce load/all db-file
clear database
if data [
foreach item data [
item: make record item
repend database [join item/code item/chknum item] ; <==<<<
ONLY THIS LINE CHANGED.
]
]
database: make hash! database
]
]
Then, search for the unique record as follows:
rec: find database join code chknum
I tested it on several records, and it seems to work perfectly.
Many thanks!
Louis
At 10:40 AM 4/15/2002 +0200, you wrote:
[15/18] from: louisaturk:eudoramail at: 15-Apr-2002 7:02
Anton,
Thanks. Little by little you are helping me understand how things
work. Thanks for your time.
Louis
At 02:53 PM 4/15/2002 +1000, you wrote:
[16/18] from: joel:neely:fedex at: 15-Apr-2002 6:50
Hi, Louis,
Dr. Louis A. Turk
wrote:
> From studying what both of you have said, I think that the root
> problem may be that I have a basic design flaw in my database.
<<quoted lines omitted: 3>>
> any keys at all! Is only one key per record
> allowed?)
...
> ... Note, however, that although the records are all unique,
> the code data is not necessarily unique, nor is the chknum data.
> There may be many records with the same code, and also many
> records with the same chknum. Only the code / chknum combination
> is unique.
>
Then my suggestion is to use a combination of those two attributes
as the key.
> So, do I perhaps need the records to look like this?:
> ] "bho" "5259" ; <===<<< TWO KEYS.
<<quoted lines omitted: 4>>
> amount: $100.00
> special: $0.00
How about
...
"bho:5259" ; <===<<< COMBINED key
make object! [
code: "bho"
chknum: "5259"
...
]
...
> all [find database code find database chknum]
>
That wouldn't work (with the "two key" version you conjectured)
because it fails (yields NONE) if neither value is present
*anywhere* in DATABASE and succeeds (yields a subseries of
DATABASE) if both values occur *somewhere* in DATABASE, but the
two occurrences could be uncorrelated...
>> database: [
[ "A" "1" #dummy
[ "B" "2" #dummy
[ "C" "3" #dummy
[ ]
== [
"A" "1" #dummy
"B" "2" #dummy
"C" "3" #dummy
]
>> all [find database "A" find database "3"]
== ["3" #dummy
]
...whereas you apparently want to know only if the *combination*
of the two values is present. If the two values may occur (with
other neighbors) multiple times, then you'd need a more complex
expression (i.e. one involving an explicit loop AFAICT) to keep
re-trying until all occurrences of one value have been checked
to see whether one of them is paired with the other value.
This way lies madness. (e.g. what happens when you need to
check a combination of 3 key fields...?)
> Am I correct about all this? If so, won't the following functions
> have to be rewritten?:
<<quoted lines omitted: 11>>
> ]
> ]
Just modify the above to contain the following instead:
foreach item data [
item: make record item
repend database [
rejoin [item/code ":" item/chknum] item
] ;item/key_field item
]
and make the corresponding changes to the other functions.
HTH!
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[17/18] from: joel:neely:fedex at: 15-Apr-2002 8:17
Hi, Anton and Louis,
Thanks, Anton, for bypassing my goof!
Anton wrote:
> Use this instead:
>
> find/skip database reduce [key1 key2] 3
>
> The skip refinement treats the series as records
> of fixed number of objects, which is 3 in this case
> (2 keys and 1 object).
>
Doh!
You're right, of course! I spoke too hastily when I said there
would be a need for a loop.
If I had thought more carefully, I would have realized that my
bias toward *ALWAYS* having a unique key was influencing my
thinking.
After further thought, I'd ask another design question:
Are the values of CODE and CHKNUM guaranteed to be immutable
over the life of an object?
If so, then the "concatenated key" approach has a slight edge
in performance, I believe.
If not, then the work required to keep the key (or keys, for
the FIND/SKIP version) up to date.
-jn-
--
; Joel Neely joeldotneelyatfedexdotcom
REBOL [] do [ do func [s] [ foreach [a b] s [prin b] ] sort/skip
do function [s] [t] [ t: "" foreach [a b] s [repend t [b a]] t ] {
| e s m!zauafBpcvekexEohthjJakwLrngohOqrlryRnsctdtiub} 2 ]
[18/18] from: louisaturk:eudoramail at: 15-Apr-2002 14:21
Joel,
It was your first post that made me realize that my problem was that I had
misunderstood how the key was used. I had just copied Carl's load-data
function without noticing that the key was not part of the
object. Everyone that contributed to this thread helped me understand what
was happening.
Your sharing of expertize is always highly appreciated.
Louis
At 08:17 AM 4/15/2002 -0500, you wrote:
Notes
- Quoted lines have been omitted from some messages.
View the message alone to see the lines that have been omitted