Page 1 of 1

Associative array for sB

Posted: Sun Apr 21, 2019 9:34 am
by Henko
Most modern programming languages have an ASSOCIATIVE ARRAY as one of the available data types. It is simply an array in wich the elements are adressable by an alphanumeric key in stead of the numeric keys (0),1,2,3,...,etc.
SmartBasic does not have such data type, but it is rather easy coded, together with the basic operations upon the elements of such an array.
In this sB program, an artificial associative array consists of two normal (string) arrays, one with the actual content and the other with the keys with wich the content may be retrieved.
Each element of the contents array is just one string. It is up to the programmer to decide about the data in that string. Data can be packed into one string using separators and be unpacked with the SPLIT command. One could see one content string as a record in a file. We will name it a record for convenience.
Access is via the keys array. The key of a desired record may be found in the keys array by at least three basic methods:
- by sequentially test each key in the keys array. This is the most simple (and slowest) method.
- By keeping the keys array sorted and use a binary search to find the desired key. This is still a relatively simple method, but much faster whith higher quantities of records.
- By using a hashing algorithm to calculate the physical location of the key in the array. This is the fastest method, but more elaborate due to the handling of synonyms (different keys, which are mapped to the same location by the hashing algoritm)
For now, i have chosen voor the simple, sequential approach. sB is fast enough that a couple of hundred elements in the string do not cause noticable processing times.
You do not have to bother about the array sizes; the size will be extended when needed (keeping their contents of course).
The arrays and the action upon them are kept in one function. The function call to this function is all that the user needs to know:

table$(opcode$,key$,content$),

Where <opcode$> is the specific action to be taken, <key$> is the key under which the content string is to be stored in the array, and <content$> is the info itself.
The opcode must always be present. Use of the other 2 parameters depend on the kind of action.
If the action completes succesfully then, unless stated otherwise, the function return an empty string. If something abnormal happens then an appropiate message string will be returned.

The function calls are:

*** table$ ("init" , "" , content$) *** : initialize the array(s).
Use content$ to pass a filename to be used for saving and loading the array contents. If not necessary, pass the empty string ("").

*** table$ ("add", key$ , content$ ) *** : add content$ to the array under the key value key$. Duplicate key are not permitted, in which case a message "key exists" will be returned

*** content$ = table$ ("get", key$ , "" ) *** : the retrieval action. The record under key value key$ will be returned. If the key does not exist, "not found" will be returned in stead.

*** table$ ("replace" , key$ , content$ ) *** : use for editting a record. content$ is overwriting the content of the record with key value key$. If the key does not exist, "not found" will be returned.

*** table$ ("del", key$ , "" ) *** : the record with key value key$ will be deleted. If the key does not exist, "not found" will be returned.

*** num = table$ ("count" , "" , "" ) *** : returns the number of records in the array (not the size of the array, that is transparant for the user)

*** tabel$ ("save" , "" , "" ) *** : save all info under the filename provided by the "init' call. If no filename is present, "noting saved" is returned.

If a non-existing opcode is entered "unknown opcode" will be returned.

This mechanism is suitable for writing simple apps about one specific object, for instance collections, properties of celestial bodies, a geneology app, etc. In the coming period i will add some tools to it, such as a sorted scrollable list with all keys, a frame for a record display window for viewing and editing. In the next post it will be used to proces a word file, producing strange results.

In my programs it will be linked in with {assoc_array}, wich is the file name under which the code is expected.

Code: Select all

' pseudo associative array for sB (version april 21, 2019)
' link in with  {assoc_array}
'
def table$(opcode$,key$,content$)
if opcode$="init" then
  .f$=content$
  if file_exists(.f$) then ! load_array(.f$) ! return "" ! end if
  N=64 ! .Ntab=N ! dim keys$(N),contents$(N) ! return ""
  end if
if opcode$="add" then
  for i=1 to N
    if keys$(i)=key$ then return "key exists"
    next i
  adr=find("")
  if adr=0 then ! adr=N+1 ! N=expand() ! end if
  keys$(adr)=key$ ! contents$(adr)=content$ ! return ""
  end if
if opcode$="get" then
  adr=find(key$) ! if adr=0 then return "not found"
  return contents$(adr)
  end if
if opcode$="replace" then
  adr=find(key$) ! if adr=0 then return "not found"
  contents$(adr)=content$ ! return ""
  end if
if opcode$="del" then
  adr=find(key$) ! if adr=0 then return "not found"
  keys$(adr)="" ! return ""
  end if
if opcode$="count" then
  num=0
  for i=1 to N ! if keys$(i)<>"" then num+=1 ! next i
  return num
  end if
if opcode$="save" then ! save_array(.f$) ! return "" ! end if
return "unknown opcode"
end def

def load_array(f$)
file f$ input .Ntab ! table$.N=.Ntab
dim table$.keys$(.Ntab),table$.contents$(.Ntab)
for i=1 to .Ntab
  file f$ input table$.keys$(i),table$.contents$(i)
  next i
end def

def save_array(f$)
if f$="" then return "nothing saved"
if file_exists(f$) then file f$ delete
file f$ print .Ntab
for i=1 to .Ntab
  if table$.keys$(i)="" then ! file f$ print """""",""""""
    else ! file f$ print table$.keys$(i),table$.contents$(i)
    end if
  next i
end def

def expand()
n=int(1.5*.Ntab)
dim a$(n),b$(n)
for i=1 to .Ntab
  a$(i)=table$.keys$(i) ! b$(i)=table$.contents$(i)
  next i
dim table$.keys$(n),table$.contents$(n)
for i=1 to .Ntab
  table$.keys$(i)=a$(i) ! table$.contents$(i)=b$(i)
  next i
.Ntab=n ! return n
end def

def find(k$)
for i=1 to .Ntab ! if table$.keys$(i)=k$ then break ! next i
if i<=.Ntab then return i else return 0
end def

Re: Associative array for sB

Posted: Mon Apr 22, 2019 6:17 pm
by Henko
Some year ago i made a program that transformed a piece of text in another text, using the same words from the original.
The first step is an analysis of the original text, establishing for each unique word all words that directly follow that word. The associative array mechanism is a perfect tool for storing those data.
The second step is a synthesis: the new text is generated by printing a keyword, then choosing randomly one of the successor words, use that word as the next keyword, print it, etc.
In general, the logic of the text as a whole is completely lost. But within each sentence, there may still be some logic.
In the demo, i use part of a Wikipedia description of black holes. You may also use your own text, if you take the folowing measures:
- the text should be saved with filename "text"
- The text file must start and end with a double quote
- Remove double quotes within the text
- Also remove carriagereturns/new-lines

Code: Select all

' text deformation program (april 22, 2019)
'
option base 1
table$("init","","")
file "text" input t$ ! lines(3) ! print t$ ! lines(3)
split t$ to w$,nw with " "
for i=1 to nw-1
  w1$=w$(i) ! w2$=w$(i+1) ! r$=table$("get",w1$,"")
  if r$="not found" then ! table$("add",w1$,w2$) ! continue
    end if
  r$&="|"&w2$ ! table$("replace",w1$,r$)
  next i
k$=table$.keys$(1) ! print k$;
for i=1 to 190
  t$=table$("get",k$,"")
  if t$="not found" then t$=table$.keys$(1)
  split t$ to w$,nw with "|"
  k$=w$(1+rnd(nw)) ! print " "&k$;
  next i  
save_array(f$)
end

{assoc_array}

def db ! debug pause ! end def
def bp(a$) = button_pressed(a$)
def lines(n) ! for i=0 to n ! print ! next i ! end def
EBBA23F9-DFD0-46C3-95CF-AF0278417B42.jpeg
EBBA23F9-DFD0-46C3-95CF-AF0278417B42.jpeg (1.61 MiB) Viewed 8720 times

Re: Associative array for sB

Posted: Tue Apr 23, 2019 2:52 am
by rbytes
Everything is working well.

How would the efficiency of this storage method compare to what we used in Datamine? - ie. speed of saving and retrieving a record.

Re: Associative array for sB

Posted: Tue Apr 23, 2019 9:49 am
by Henko
There are principal differences between datamine and the associative array (short: array) method:

If we recognize difference between internal and external memory, then datamine keeps all data on external ("permanent") memory. Only one record at the time is kept in internal memory.
With the array method, all data is kept in internal memory as long as the program is active. On an iDevice, there is little to no difference in speed between internal and external memory (although i am not sure about that). On a laptop with SSD there is a significant difference, and on a PC with harddisc, there is a huge difference.

Safety: with the array method, if the program quits for whatever reason without the (modfied) array being saved, all modifications are lost. With Datamine, one modification at maximum is lost.
Hence for a serious application, Datamine is the preferred solution. The array method is good for fast prototyping and applications with a (very) low mutation level.

Efficiency: array method uses the most simple and slow retrieve method. When the array contains N records, the average number of accesses to retrieve a record is N/2, hence lineair dependent on the size of the "database".
Datamine uses the fastest retrieve method: on average between 1 and 1.5 accesses per retrieval, independent of the size of the database.
In practice the delay during a retrieval will not be noticed on an iDevice if the array / database contains a couple of hundred records. On a laptop with SSD that threshold would be somewhat lower, and on a device with harddisc the speed difference in favor of Datamine would readily be noticed.
But as pointed out in the first post in this thread: the array method could also be equiped with the fast hashing method, but we already have Datamine at our disposal.

Versatility: Datamine has some more functionality. I think Datamine requires less programming to turn it into an app. On the other hand, the interface (call it the API) of the current array method is very simple to understand.

Re: Associative array for sB

Posted: Tue Apr 23, 2019 1:39 pm
by rbytes
Thanks for doing the comparison. 8-)

Re: Associative array for sB

Posted: Tue Apr 23, 2019 3:21 pm
by Henko
Next, i will make a "collection management" app.
Besides my programming hobby, my second hobby is Whisky. My "stock" varies between 25 and 30 bottles, from wich about half opened and ready for "sniffing and tasting" :mrgreen:
It may seem a lot of bottles, but in the world of real whisky lovers i am but a dwarf, and do not dare to raise my voice on the Dutch whisky forum.

So, i will make an app to register and manage my whisky. I will do it in such a way that the app may serve as a template for other "collection" apps. Other people may collect precious stones, or banknotes, etc.

First, one has to design a data model: what data to register and how to organize them. I've done that and the result is a viewing/editing window with the selected data (displayed herafter). As the associative array method is used, a short key is to be defined for each item (in this case a brand of whisky). Furtemore, the datamodel for this app has two hierarchical levels: one of the 1st level items is the riping method for that brand, and the riping method consists of a variable number of cask types where the whisky has spent his youth. The casks form the second level. As all data have to be packed into one string for one brand, we will use different separators, one for each hierarchical level.

Todays release of the whisky management app is no more than the initialization of the associative array mechanism and the whisky window definition and putting it on the screen.
In the next versions, a scrolling list with the keys will be added, which is an aid for viewing, adding, editing, and deleting whisky records.
89F81BA4-EB15-47C8-833D-9799972E1DB4.png
89F81BA4-EB15-47C8-833D-9799972E1DB4.png (326.5 KiB) Viewed 8699 times

Code: Select all

' Whisky management (version april 23, 2019)
'
init_prog()
page "whisky" show
pause 3
end

def init_prog()
option base 1
graphics ! graphics clear .8,.8,.8 ! draw color 0,0,0
table$("init","","whisky")
whisky_window("whisky","Whisky",350,20,400,500,.5,.7,.7)
end def

def whisky_window(name$,title$,xs,ys,ww,hh,R,G,B)
        ' **** stuff for all input forms ***
page name$ set ! page name$ frame xs,ys,ww,hh
page name$ color R,G,B,0
fill color R,G,B ! set buttons custom
button name$&"win" text "" at 0,0 size ww,hh ! set buttons default
button name$&"title" text title$ at 1,1 size ww-2,27
        ' *** application specific fields ***
n$=" Key : "
field name$ & "key" text n$ at 10,40 size 150,40 RO
field name$ & "_key" text "" at 160,40 size 100,40
field_refine(name$ & "key")
n$=" Full name: "
field name$ & "name" text n$ at 10,90 size 150,40 RO
field name$ & "_name" text "" at 160,90 size 220,40
field_refine(name$ & "name")
n$=" Years of riping: "
field name$ & "yrs" text n$ at 10,140 size 150,40 RO
field name$ & "_yrs" text "" at 160,140 size 100,40
field_refine(name$ & "yrs")
n$=" Strenght %: "
field name$ & "alco" text n$ at 10,190 size 150,40 RO
field name$ & "_alco" text "" at 160,190 size 100,40
field_refine(name$ & "alco")
n$=" Cask1: "
field name$ & "cask1" text n$ at 10,240 size 150,40 RO
field name$ & "_cask1" text "" at 160,240 size 220,40
field_refine(name$ & "cask1")
n$=" Cask2: "
field name$ & "cask2" text n$ at 10,290 size 150,40 RO
field name$ & "_cask2" text "" at 160,290 size 220,40
field_refine(name$ & "cask2")
n$=" Cask3: "
field name$ & "cask3" text n$ at 10,340 size 150,40 RO
field name$ & "_cask3" text "" at 160,340 size 220,40
field_refine(name$ & "cask3")
n$=" # Bottles: "
field name$ & "quant" text n$ at 10,390 size 150,40 RO
field name$ & "_quant" text "" at 160,390 size 100,40
field_refine(name$ & "quant")
n$=" Price/bottle: "
field name$ & "price" text n$ at 10,440 size 150,40 RO
field name$ & "_price" text "" at 160,440 size 100,40
field_refine(name$ & "price")

page name$ hide ! page "" set
end def

def field_refine(f$)
field f$ font size 24 ! field f$ font color 1,1,0
field f$ back color .5,.7,.7 ! field f$ back alpha .2
field f$ font name "Baskerville-Italic"
end def

' sorting 2 coupled string arrays (option base 1 assumed)
' n = size of arrays
' a$() = array to be sorted
' b$() = array to be sorted in same order as a$()
'
def duosort (n,a$(),b$())
dim index(n),temp$(n)
sort a$ as index
for i=1 to n ! temp$(i)=a$(index(i)) ! next i
for i=1 to n ! a$(i)=temp$(i) ! next i
for i=1 to n ! temp$(i)=b$(index(i)) ! next i
for i=1 to n ! b$(i)=temp$(i) ! next i
for i=1 to n ! if a$(i)<>"" then break ! next i
k=i-1
dim .list$(n-k)
for i=1 to n-k
  if k then ! a$(i)=a$(i+k) ! b$(i)=b$(i+k) ! end if
  .list$(i)=a$(i)
  next i
if k then
  for i=n-k+1 to n ! a$(i)="" ! next i
  end if
return
end def

{assoc_array}

Re: Associative array for sB

Posted: Wed Apr 24, 2019 11:08 am
by Henko
Yesterday's version has been extended by the following items:
- the whisky window has been shifted left to create space for the function buttons. There is still enough space on the left side of the screen for the scrolling list with the keys.
- The function buttons have been defined and placed at the right side of the screen. These are basic functions. There will be more in the future; there is place enough for them.
- The main program is nearly completed, using the presently forseen tasks. Each task has been given a function name and body (wich is yet empty). The main program works in a "event driven" way: it sits, and waits till something happens (the user, touching a button or a key in the scrollable list).
- The user may save his work at any time using the "Save" button. To ensure that the save is not forgotten, a variable "array_changed" is used. It is initialized to zero in the init_program function. It will be set in the functions, which modify the array, and will be reset to zero in the save function itself. Upon quitting the app the variable is checked to see if saving is necessary.
We already have a lot of code and it works syntax error free, but yet only the "quit" button is fully functional.

Next will be coding the "add" function, in order that a test array can be built for the other functions.

39E8283F-F8F4-41CC-BB1B-9F852D31336E.png
39E8283F-F8F4-41CC-BB1B-9F852D31336E.png (348.76 KiB) Viewed 8681 times
' Whisky management app (version april 24,2019)
'
init_prog()
do slowdown
key$="" ' to be replaced by a scan of the scrollable list
' and the viewing code
if bp("add") then add_brand(key$)
if bp("edit") then replace_brand(key$)
if bp("del") then delete_brand(key$)
if bp("sort") then sort_array()
if bp("save") then save_array(f$)
until bp("quit")
if array_changed then save_array(f$)
end

def init_prog()
option base 1
graphics ! graphics clear .8,.8,.8 ! draw color 0,0,0
table$("init","","whisky")
whisky_window("whisky","Whisky",190,20,400,500,.5,.7,.7)
set buttons custom ! set buttons font size 20
set buttons font name "Georgia-Bold" ! fill color .5,.7,.7
button "add" text "Add" at 620,50 size 120,40
button "edit" text "Replace" at 620,120 size 120,40
button "del" text "Delete" at 620,190 size 120,40
button "sort" text "Sort" at 620,280 size 120,40
button "save" text "Save" at 620,350 size 120,40
button "quit" text "Quit" at 620,480 size 120,40
.array_changed=0
end def

def add_brand(key$)
end def

def replace_brand(key$)
end def

def delete_brand(key$)
end def

def sort_array()
end def

def whisky_window(name$,title$,xs,ys,ww,hh,R,G,B)
' **** stuff for all input forms ***
page name$ set ! page name$ frame xs,ys,ww,hh
page name$ color R,G,B,0
fill color R,G,B ! set buttons custom
button name$&"win" text "" at 0,0 size ww,hh ! set buttons default
button name$&"title" text title$ at 1,1 size ww-2,27
' *** application specific fields ***
n$=" Key : "
field name$ & "key" text n$ at 10,40 size 150,40 RO
field name$ & "_key" text "" at 160,40 size 100,40
field_refine(name$ & "key")
n$=" Full name : "
field name$ & "name" text n$ at 10,90 size 150,40 RO
field name$ & "_name" text "" at 160,90 size 220,40
field_refine(name$ & "name")
n$=" Years of riping : "
field name$ & "yrs" text n$ at 10,140 size 150,40 RO
field name$ & "_yrs" text "" at 160,140 size 100,40
field_refine(name$ & "yrs")
n$=" Strenght % : "
field name$ & "alco" text n$ at 10,190 size 150,40 RO
field name$ & "_alco" text "" at 160,190 size 100,40
field_refine(name$ & "alco")
n$=" Cask1 : "
field name$ & "cask1" text n$ at 10,240 size 150,40 RO
field name$ & "_cask1" text "" at 160,240 size 220,40
field_refine(name$ & "cask1")
n$=" Cask2 : "
field name$ & "cask2" text n$ at 10,290 size 150,40 RO
field name$ & "_cask2" text "" at 160,290 size 220,40
field_refine(name$ & "cask2")
n$=" Cask3 : "
field name$ & "cask3" text n$ at 10,340 size 150,40 RO
field name$ & "_cask3" text "" at 160,340 size 220,40
field_refine(name$ & "cask3")
n$=" # Bottles : "
field name$ & "quant" text n$ at 10,390 size 150,40 RO
field name$ & "_quant" text "" at 160,390 size 100,40
field_refine(name$ & "quant")
n$=" Price/bottle : "
field name$ & "price" text n$ at 10,440 size 150,40 RO
field name$ & "_price" text "" at 160,440 size 100,40
field_refine(name$ & "price")
page "" set
end def

def field_refine(f$)
field f$ font size 24 ! field f$ font color 1,1,0
field f$ back color .5,.7,.7 ! field f$ back alpha .2
field f$ font name "Baskerville-Italic"
end def

' sorting 2 coupled string arrays (option base 1 assumed)
' n = size of arrays
' a$() = array to be sorted
' b$() = array to be sorted in same order as a$()
'
def duosort (n,a$(),b$())
dim index(n),temp$(n)
sort a$ as index
for i=1 to n ! temp$(i)=a$(index(i)) ! next i
for i=1 to n ! a$(i)=temp$(i) ! next i
for i=1 to n ! temp$(i)=b$(index(i)) ! next i
for i=1 to n ! b$(i)=temp$(i) ! next i
for i=1 to n ! if a$(i)<>"" then break ! next i
k=i-1
dim .list$(n-k)
for i=1 to n-k
if k then ! a$(i)=a$(i+k) ! b$(i)=b$(i+k) ! end if
.list$(i)=a$(i)
next i
if k then
for i=n-k+1 to n ! a$(i)="" ! next i
end if
return
end def

{assoc_array}

def db ! debug pause ! end def
def bp(a$) = button_pressed(a$)

Re: Associative array for sB

Posted: Fri Apr 26, 2019 4:52 pm
by Henko
The forelast version. The selection list has been added, and the remaining basic functions have been coded. A collection of whisky have been entered via the app in a file. The file with whiskies is given after the code file. The last version will be used for some refinements and a reporting function.
The contents of the "assoc_array" file can be found in the first posting of this thread.
Remember that changes in the content of a field is only accepted with the "return" key.
B751C3C6-2D7C-4F99-B0DB-8B9E08B07BD5.png
B751C3C6-2D7C-4F99-B0DB-8B9E08B07BD5.png (394.03 KiB) Viewed 8656 times

Code: Select all

' Whisky management app (version april 26,2019)
'
init_prog()
do slowdown
  lnr=list_selected("whisky")
  if lnr>0 then
    key$=table$.keys$(lnr) ! display(key$)
    list "whisky" select -1
    end if
  if bp("add")  then add_brand()
  if bp("edit") then replace_brand(key$)
  if bp("del")  then delete_brand(key$)
  if bp("sort") then reorganize_array()
  if bp("save") then save_array(f$)
  until bp("quit")
if array_changed then save_array(f$)
end

def init_prog()
option base 1
graphics ! graphics clear .8,.8,.8 ! draw color 0,0,0
table$("init","","whisky")
whisky_window("whisky","Whisky",190,20,400,500,.5,.7,.7)
set buttons custom ! set buttons font size 20
set buttons font name "Georgia-Bold" ! fill color .5,.7,.7
button "add" text "Add" at 620,50 size 120,40
button "edit" text "Replace" at 620,120 size 120,40
button "del" text "Delete" at 620,190 size 120,40
button "sort" text "Reorg" at 620,280 size 120,40
button "save" text "Save" at 620,350 size 120,40
button "quit" text "Quit" at 620,480 size 120,40
.array_changed=0 ! reorganize_array()
end def

def display(key$)
field "whisky_key" text key$
cont$=table$("get",key$,"")
split cont$ to rec$,nrec with "|"
field "whisky_name" text rec$(1)
field "whisky_yrs" text rec$(2)
field "whisky_alco" text rec$(3)
field "whisky_quant" text rec$(5)
field "whisky_price" text rec$(6)
split rec$(4) to cas$,nrec with ","
for i=1 to 3 ! field "whisky_cask"&i text "" ! next i
for i=1 to nrec ! field "whisky_cask"&i text cas$(i) ! next i
end def

def add_brand()
key$=field_text$("whisky_key") ! if key$="" then return
content$ = window_content$()
table$("add",key$,content$) ! .array_changed=1
end def

def replace_brand(key$)
key$=field_text$("whisky_key") ! if key$="" then return
content$ = window_content$()
table$("replace",key$,content$) ! .array_changed=1
end def

def delete_brand(key$)
key$=field_text$("whisky_key") ! if key$="" then return
table$("del",key$,"")
end def

def whisky_window(name$,title$,xs,ys,ww,hh,R,G,B)
        ' **** stuff for all input forms ***
fill color R,G,B ! set buttons custom
button name$&"win" text "" at xs,ys size ww,hh
x1=xs+10 ! x2=xs+160 ! set buttons default
button name$&"title" text title$ at xs+1,ys+1 size ww-2,30
        ' *** application specific fields ***
n$=" Key : "
field name$ & "key" text n$  at x1,ys+40 size 150,40 RO
field name$ & "_key" text "" at x2,ys+40 size 100,40
field_refine(name$ & "key")  ! ys+=90
n$=" Full name : "
field name$ & "name" text n$  at x1,ys size 150,40 RO
field name$ & "_name" text "" at x2,ys size 220,40
field_refine(name$ & "name")  ! ys+=50
n$=" Years of riping : "
field name$ & "yrs" text n$  at x1,ys size 150,40 RO
field name$ & "_yrs" text "" at x2,ys size 100,40
field_refine(name$ & "yrs")  ! ys+=50
n$=" Strenght % : "
field name$ & "alco" text n$  at x1,ys size 150,40 RO
field name$ & "_alco" text "" at x2,ys size 100,40
field_refine(name$ & "alco")  ! ys+=50
n$=" Cask1 : "
field name$ & "cask1" text n$  at x1,ys size 150,40 RO
field name$ & "_cask1" text "" at x2,ys size 220,40
field_refine(name$ & "cask1")  ! ys+=50
n$=" Cask2 : "
field name$ & "cask2" text n$  at x1,ys size 150,40 RO
field name$ & "_cask2" text "" at x2,ys size 220,40
field_refine(name$ & "cask2")  ! ys+=50
n$=" Cask3 : "
field name$ & "cask3" text n$  at x1,ys size 150,40 RO
field name$ & "_cask3" text "" at x2,ys size 220,40
field_refine(name$ & "cask3")  ! ys+=50
n$=" # Bottles : "
field name$ & "quant" text n$  at x1,ys size 150,40 RO
field name$ & "_quant" text "" at x2,ys size 100,40
field_refine(name$ & "quant")  ! ys+=50
n$=" Price/bottle : "
field name$ & "price" text n$  at x1,ys size 150,40 RO
field name$ & "_price" text "" at x2,ys size 100,40
field_refine(name$ & "price")
end def

def field_refine(f$)
field f$ font size 24 ! field f$ font color 1,1,0
field f$ back color .5,.7,.7 ! field f$ back alpha .2
field f$ font name "Baskerville-Italic"
end def

def window_content$()
content$ = field_text$("whisky_name")
content$ &= "|" & field_text$("whisky_yrs")
content$ &= "|" & field_text$("whisky_alco")
content$ &= "|" & field_text$("whisky_cask1")
cask$=field_text$("whisky_cask2")
if cask$<>"" then content$ &= "," & cask$
cask$=field_text$("whisky_cask3")
if cask$<>"" then content$ &= "," & cask$
content$ &= "|" & field_text$("whisky_quant")
content$ &= "|" & field_text$("whisky_price")
return content$
end def

def reorganize_array()
n=0
dim key$(.Ntab),cont$(.Ntab)
for i=1 to .Ntab
  k$=table$.keys$(i) ! if k$="" then continue
  n+=1 ! key$(n)=k$ ! cont$(n)=table$.contents$(i)
  next i
dim list$(n)
for i=1 to .Ntab 
  if i<=n then
    list$(i)=key$(i)
    table$.keys$(i)=key$(i) ! table$.contents$(i)=cont$(i)
    else ! table$.keys$(i)=""
    end if
  next i
sort list$ as index
for i=1 to n ! key$(i)=table$.keys$(index(i)) ! next i
for i=1 to n ! table$.keys$(i)=key$(i) ! list$(i)=key$(i) ! next i
for i=1 to n ! cont$(i)=table$.contents$(index(i)) ! next i
for i=1 to n ! table$.contents$(i)=cont$(i) ! next i
for i=1 to n ! if table$.keys$(i)<>"" then break ! next i
c_list("whisky","Key's",list$,n,20,20,150,500)
end def

' id$ = object name
' cont$ = array met elementen
' size = aantal elementen in de list
'
def c_list(id$,title$,cont$(),size,xt,yt,ww,hh)
fill color .5,.7,.7 ! set buttons custom
button name$&"win" text "" at xt,yt size ww,hh
x1=xs+10 ! x2=xs+160 ! set buttons default
button name$&"title" text title$ at xt+1,yt+1 size ww-2,30
list id$ text cont$ at xt+8,yt+37 size ww-16,hh-45
end def

{assoc_array}

def db ! debug pause ! end def
def bp(a$) = button_pressed(a$)

The file to be named "whisky" :

Code: Select all

 64 
ar           Arran|NAS|50|bourbon,port|0.8|48
bm           Bushmills|10|40|bourbon,oloroso|0.3|22
br-m         Benriach_Madeira|15|46|bourbon,madeira|1|75
br-sa        Benriach_Sauternes|16|46|bourbon,sauternes|0.15|85
br-sh        Benriach_Sherry|12|46|oloroso,pedro_ximenez|1|36
gd-a         Glendronach_Allardice|18|46|oloroso|4.6|76
gd-cs        Glendronach_cask_strenght|NAS|55.3|oloroso,pedro_ximenez|0.5|66
gd-o         Glendronach_original|12|43|oloroso,pedro_ximenez|4.3|24
gd-p         Glendronach_Parliament|21|48|oloroso,pedro_ximenez|1.2|110
gd-r         Glendronach_Revival|15|46|oloroso|1|80
gd-s12       Glendronach_Sauternes|12|46|sherry,sauternes|1|70
gd-s14       Glendronach_Sauternes|14|46|sherry,sauternes|1|170
gd-tp        Glendronach_Tawny_Port|15|46|sherry,port|1|85
gm-las       Glenmorangie_Lasanta|12|43|bourbon,oloroso,pedro_ximenez|0.9|46
gm-no        Glenmorangie_Nectar_d'or|12|46|bourbon,sauternes|0.15|53
gm-o         Glenmorangie_Original|10|40|bourbon|0.15|28
gm-qr        Glenmorangie_Quinta_Ruban|12|46|bourbon,port|0.75|46
mac          Macallan_Fine_Oak|12|40|bourbon,sherry|0.99|45
tal          Talisker|10|45.8|bourbon|0.35|35
tal-pr       Talisker_Port_Ruighe|NAS|45.8|bourbon,port|0.5|40
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""
""           ""

Re: Associative array for sB

Posted: Fri Apr 26, 2019 5:07 pm
by Henko
Two additional explanations about the used quantities:

"NAS" in stead of a number of years riping is commonly used to indicate "No Age Statement".
Scottish law does not force whisky companies to mention the "age" (the number of years that a whisky ripes in one or more casks), but if they put the age on the bottle, it must be the age of the youngest whisky the used in the whisky batch. There are a couple of well known, and excellent NAS whiskies, but newly marketed brands with a NAS label on the bottle are regarded suspiciously by the "connaisseurs".

Quantity:
0 - .99 : an open bottle, filled partly with the given fraction of a full bottle.
1 : a full bottle, still sealed
3.35 : 3 full bottles (sealed) and one open bottle filled about one third