:TITLE: Associative Arrays.
;#
;# RCSID: $Header: /home/cvs/TclTutor3/lesson/Tcl/Tcl22.lsn,v 1.1.1.1 2007/09/15 13:30:24 clif Exp $
;# Copyright (c) 1995 Clif Flynt
;# 9300 Fleming Rd.
;# Dexter, MI  48130
;# clif@cflynt.com
;# See file "NOTICE" for licensing terms.
;#
:LESSON_TEXT_START_LEVEL 0:
Like awk and perl, Tcl supports associative arrays.  
<P>
The syntax for an associative array is to put the index within parentheses.
<P>
There are several array commands aside from simply accessing and creating
arrays which will be discussed in this and the next lesson.
<DL>
<B><DT>array exists</B> <I>arrayName</I>
<DD> Returns 1 if <I>arrayName</I> is an array variable.  Returns 0
if <I>arrayName</I> is a scalar variable, proc, or does not exist.
<B><DT>array names</B> <I>arrayName</I> <I>?pattern</I>
<DD>Returns a list of the indices for the associative array <I>arrayName</I>.
If <I>pattern</I> is supplied, only those indices that match <I>pattern</I> are
returned.  The match is done using the globbing technique from <I>string match</I>.
<B><DT>array size</B> <I>arrayName</I>
<DD>Returns the number of elements in array <I>arrayName</I>.
<B><DT>array get</B> <I>arrayName</I>
<DD>Returns a list in which each odd member of the list (1, 3, 5, etc) is
an index into the associative array.  The list element following a name
is the value of that array member.
<B><DT>array set</B> <I>arrayName dataList</I>
<DD>Converts a list into an associative array.
<I>DataList</I> is a list in the format of that returned by <I>array get</I>.
Each odd member of the list (1, 3, 5, etc) is
an index into the associative array, and the list element following that
is the value of that array member.  
</DL>
<P>
When an associative array name is given as the argument to the
<CODE>global</CODE> command, all the elements of the associative array
become available to that proc.  For this reason, <I>Brent Welch</I>
recommends ( in <UL>Practical Programming in Tcl and Tk</UL>) using an
associative array for the state structure in a package.

:TEXT_END:

:LESSON_TEXT_START_LEVEL 1:
Languages like C, BASIC and FORTRAN support arrays in which the index value
is an integer.  Tcl, like Awk and perl supports associative arrays in which the
index value is a string.
<P>
The syntax for an associative array is to put the index within parentheses.
<P>
There are several array commands aside from simply accessing and creating
arrays which will be discussed in this and the next lesson.
<DL>
<B><DT>array exists</B> <I>arrayName</I>
<DD> Returns 1 if <I>arrayName</I> is an array variable.  Returns 0
if <I>arrayName</I> is a scalar variable, proc, or does not exist.
<B><DT>array names</B> <I>arrayName</I> <I>?pattern</I>
<DD>Returns a list of the indices for the associative array <I>arrayName</I>.
If <I>pattern</I> is supplied, only those indices that match <I>pattern</I> are
returned.  The match is done using the globbing technique from <I>string match</I>.
<B><DT>array size</B> <I>arrayName</I>
<DD>Returns the number of elements in array <I>arrayName</I>.
<B><DT>array get</B> <I>arrayName</I>
<DD>Returns a list in which each odd member of the list (1, 3, 5, etc) is
an index into the associative array.  The list element following a name
is the value of that array member.
<B><DT>array set</B> <I>arrayName dataList</I>
<DD>Converts a list into an associative array.
<I>DataList</I> is a list in the format of that returned by <I>array get</I>.
Each odd member of the list (1, 3, 5, etc) is
an index into the associative array, and the list element following that
is the value of that array member.  
</DL>
<P>
When an associative array name is given as the argument to the
<CODE>global</CODE> command, all the elements of the associative array
become available to that proc.  For this reason, <I>Brent Welch</I>
recommends ( in <UL>Practical Programming in Tcl and Tk</UL>) using an
associative array for the state structure in a package.  
<P>
This method makes it simpler to share data between many procs that are
working together, and doesn't pollute the global namespace as badly as
using separate globals for all shared data items.

:TEXT_END:

:LESSON_TEXT_START_LEVEL 2:
There are three simple data types in Tcl; the list, the string, and the
associative array.  An associative array is a collection of data elements
similar to a list.  In a list, every element has a location, and you can
access a data element by that location (with the <CODE>lindex</CODE>command).
With associative arrays, every data element has a name as well as a value,
and you can access a particular element by its name.  
<P>
An item in an associative array is described by a string in this format:
<CODE>arrayName(elementName)</CODE>.  As with regular variables, you can
set the value of an element in an array with a commands like: 
<PRE><CODE>
set chores(Sunday) "Wash Car";  
set chores(Monday) "Take out Garbage"
set chores(Tuesday) [list {Clean Fridge} {Go shopping} {Call Mom}];
</CODE></PRE>
There are several array commands aside from simply accessing and creating
arrays which will be discussed in this and the next lesson.
<DL>
<B><DT>array exists</B> <I>arrayName</I>
<DD> Returns 1 if <I>arrayName</I> is an array variable.  Returns 0
if <I>arrayName</I> is a scalar variable, proc, or does not exist.
<B><DT>array names</B> <I>arrayName</I> <I>?pattern</I>
<DD>Returns a list of the indices for the associative array <I>arrayName</I>.
If <I>pattern</I> is supplied, only those indices that match <I>pattern</I> are
returned.  The match is done using the globbing technique from <I>string match</I>.
<B><DT>array size</B> <I>arrayName</I>
<DD>Returns the number of elements in array <I>arrayName</I>.
<B><DT>array get</B> <I>arrayName</I>
<DD>Returns a list in which each odd member of the list (1, 3, 5, etc) is
an index into the associative array.  The list element following a name
is the value of that array member.
<B><DT>array set</B> <I>arrayName dataList</I>
<DD>Converts a list into an associative array.
<I>DataList</I> is a list in the format of that returned by <I>array get</I>.
Each odd member of the list (1, 3, 5, etc) is
an index into the associative array, and the list element following that
is the value of that array member.  
</DL>
<P>
When an associative array name is given as the argument to the
<CODE>global</CODE> command, all the elements of the associative array
become available to that proc.  For this reason, <I>Brent Welch</I>
recommends ( in <UL>Practical Programming in Tcl and Tk</UL>) using an
associative array for the state structure in a package.  
<P>
This method makes it simpler to share data between many procs that are
working together, and doesn't pollute the global namespace as badly as
using separate globals for all shared data items.
<P>
For example, consider a program which has several procs for handling
different calculations each of which has a subtotal that has to be
carried forward from proc to proc, and all feed into the same total.
You could handle it like this:

<PRE><CODE>
proc proc1 {} {
  global subtotal1, total;
  ...
  }

proc proc2 {} {
  global subtotal2, total;
  ...
  }
...
</CODE></PRE>
or like this
<PRE><CODE>
proc proc1 {} {
  global data;
  set data(subtotal1) ...
  }

proc proc2 {} {
  global data;
  set data(subtotal2) ...
  }
...
</CODE></PRE>
In the second method, there is only one global variable name created.  This
give you a much lower chance of colliding with other global variables when
you merge your set of procs with other peoples code to make new programs.
<P>
Using the associative array also makes it easier to add a new field if
it becomes necessary.  You can just add the new data element to the associative
array, and it becomes available to any procs that need to access it.
<P>
A fairly common bug in Tcl programs is neglecting to put in the <CODE>global</CODE>
command for a global variable.  If this happens, Tcl will silently make a local
variable with the same name as the global variable, and will use it in that
proc, but any changes you make to that variable won't be reflected in the global
scope, and the current state of the global variable won't be available in the
proc.  This creates code that is syntactically correct, but doesn't produce the
expected results.
:TEXT_END:

:CODE_START:
array set array1 [list {123} {Abigail Aardvark} \
		       {234} {Bob Baboon} \
                       {345} {Cathy Coyote} \
		       {456} {Daniel Dog} ]

puts "Array1 has [array size array1] entries\n"

puts "Array1 has the following entries: \n [array names array1] \n"

puts "ID Number 123 belongs to $array1(123)\n"

if {[array exist array1]} {
   puts "array1 is an array"
   } else {
   puts "array1 is not an array"
   }

if {[array exist array2]} {
   puts "array2 is an array"
   } else {
   puts "array2 is not an array"
   }

:TEXT_END:

