|
| |
| pickyh3d | Asp.Net User |
| Associative Array | 12/22/2006 2:21:57 AM |
0/0 | |
|
I've been sick and bored for awhile, and among other things, I've been trying to get my mind off of both. Anyway, I have been messing around with an AssociativeArray class similar to PHP's that does not require a bunch of tricks or weird checks. The biggest difference between this class and PHP's built-in associative arrays is that this class changes how you access the data from ["x"]["y"]["z"] to ["x", "y", "z"] unless you're willing to do a bunch of casting or using it in a loop.
There is some example code (for a console application) below the AssociativeArray class, that shows how to use it a little. If anyone finds any issues, then please let me know and I'll try to work them out in my spare time. Hopefully this helps out a few PHP developers while they're making the switch (though I'm not so sure that I'd suggest using this long term, but short term code needs may make this useful).
using System;
using System.Collections;
namespace AssociativeArray
{
/// <summary>
/// A collection of key/value pairs that is made so that it can be used similarly to PHP's associative arrays.
///
/// Note that the biggest limitation is that there is no type checking between keys or values, so '1'c does not equal "1", which is still different from 1L and 1I (1i), and the many other numerical data types (1D, et cetera).
/// </summary>
class AssociativeArray : CollectionBase, IDictionary, IEnumerable
{
/// <summary>
/// The keys array, which matches the built-in List (ArrayList) in size, holds every supplied key.
/// </summary>
protected ArrayList m_alKeys = null;
/// <summary>
/// In the event that users want to syncronize this object for thread safety, then they need to do it themselves.
///
/// Unfortunately, the syncronization only applies to THIS level of the associative array.
/// </summary>
protected object m_objSyncRoot = null;
/// <summary>
/// Get the Keys array list.
/// </summary>
protected virtual ArrayList Keys
{
get { return m_alKeys; }
}
/// <summary>
/// Get/set an key/value pair in the associative array.
///
/// When GETTING a value, if the key is an integer that does not exist in the key list, it is checked as an index. If the index exists, then it returns that value.
/// Use the GetValue(object) function to avoid this functionality.
///
/// When SETTING a value, if the key does not exist, then it is added to the list with the passed value.
/// </summary>
/// <param name="objKey">The key to get/set the value for--may be null (Nothing in VB.NET).</param>
/// <returns>Returns the object for the specified key, or index if the key does not exist, but is a valid zero-based index. If the key does not exist, then null (Nothing in VB.NET) is returned.</returns>
public virtual object this [ object objKey ]
{
get
{
// the returned object
object objReturned = GetValue(objKey);
// if the above method did not work, then see if we were maybe passed an index
if ( objReturned == null && objKey is int )
{
// it's an integer, so cast it as one and try to get the element's value
return GetValue((int)objKey);
}
// the returned object--still may be null
return objReturned;
}
set
{
// edit the specified key, or add it if it does not exist
Edit(objKey, value);
}
}
/// <summary>
/// Get/set a nested associative array key/value.
///
/// When GETTING a value, if any key is an integer that does not exist in the key list, it is checked as an index. If the index exists, then it returns that value. In case neither work, then null (Nothing in VB.NET) is returned.
///
/// When SETTING a value, if the key does not exist, then it is added to the list with the passed value. Any keys that do not exist, or exist as something other than an associative array are OVERWRITTEN as AssociativeArray objects and nested appropriately.
/// </summary>
/// <param name="objKeys">The keys to get/set, in order. Individual keys may be null.</param>
/// <returns>Returns the object for the specified key, or index if the key does not exist, but is a valid zero-based index. If the key does not exist, then null (Nothing in VB.NET) is returned.</returns>
/// <example>
/// // I would not actually use this example for what it does, but I think the example makes it clear.
/// AssociativeArray Temp = new AssociativeArray();
/// string AnonymousUserKey = null;
///
/// Temp["users", "picky", "id"] = "3213";
/// Temp["users", "picky", "admin"] = true; // boxed value [struct]
///
/// Temp["users", null, "id"] = "0";
/// Temp["users", null, "admin"] = false; // boxed value [struct]
///
/// if ( (bool)Temp["users", AnonymousUserKey, "admin"] )
/// {
/// // the user is an admin
/// }
/// else
/// {
/// // the user is NOT an admin
/// }
///
/// --cmt:f8cf39c1-2685-4a69-81b4-40208d24e7a7--
///
/// </example>
public object this [ params object []objKeys ]
{
get
{
// invalid parameters
if ( objKeys == null || objKeys.Length == 0 )
{
// we're done--nothing to return
return null;
}
// used in while loop (skip first element--already retrieved right below)
int i = 1;
// every key except the last must be an AssociativeArray, or else it will return null.
AssociativeArray aaArray = this[objKeys[0]] as AssociativeArray;
// loop until the last element, or stop if any element inbetween is not an Associative Array
while ( aaArray != null && i < objKeys.Length - 1 )
{
// try to get the next array
aaArray = aaArray[objKeys[i++]] as AssociativeArray;
}
// if the last element was not an Associative Array, then we are done and have found nothing
if ( aaArray == null )
{
// nothing found--stop
return null;
}
// the returned object; may be null
return aaArray[objKeys[i]];
}
set
{
// invalid parameters
if ( objKeys == null || objKeys.Length == 0 )
{
// we're done
return;
}
// used in while loop (skip first element--already retrieved right below)
int i = 0;
// every key except the last must be an AssociativeArray, and this will make that the case
AssociativeArray aaArray = this;
// temp used so we do not lose the last array's reference in case an element is not an Associative Array
AssociativeArray aaTempArray = null;
// loop until the last element
// if any element in between is not an AssociativeArray, then they become one
while ( i < objKeys.Length - 1 )
{
// try to get the next array
aaTempArray = aaArray[objKeys[i]] as AssociativeArray;
// in case the element is not an associative array, then we must make it one
// this will remove whatever was there before
if ( aaTempArray == null )
{
// create the new associative array
aaTempArray = new AssociativeArray();
aaArray[objKeys[i]] = aaTempArray;
aaArray = aaTempArray;
}
else // the element was an Associative Array, so get the reference to it
{
// get the reference
aaArray = aaTempArray;
}
// next sub-element
++i;
}
// finally add/edit the specified value
aaArray.Edit(objKeys[i], value);
}
}
/// <summary>
/// Add a key/value pair. Both values may be null (Nothing in VB.NET), but there may only be ONE null key per Associative Array (sub-arrays may have their own null keys).
///
/// If the key already exists, then the value with be modified.
/// </summary>
/// <param name="objKey">The key to add associated to the value.</param>
/// <param name="objValue">The value to add associated to the key.</param>
public virtual void Add ( object objKey, object objValue )
{
// if it does ALREADY exist, then edit it
if ( Keys.Contains(objKey) )
{
// edit it
Edit(objKey, objValue);
// we're done
return;
}
// add the KEY can be null
Keys.Add(objKey);
// add the VALUE
InnerList.Add(objValue);
}
/// <summary>
/// Equivalent to calling Add(null, objValue).
///
/// Note, there may only be one null key at any time per Associative Array.
/// </summary>
/// <param name="objValue">The value to add to the associative array with no key.</param>
public virtual void Add ( object objValue )
{
// just call the other overload with no key
Add(null, objValue);
}
/// <summary>
/// Edit an existing key/value pair by changing only the value.
///
/// If the key does not exist, then it will be added.
/// </summary>
/// <param name="objKey">The existing key to associate with the value.</param>
/// <param name="objValue">The value to set the associate with the key.</param>
protected virtual void Edit ( object objKey, object objValue )
{
// used to
int intIndex = Keys.IndexOf(objKey);
// if it does NOT exist, then add it
if ( intIndex == -1 )
{
// add it
Add(objKey, objValue);
// we're done
return;
}
// change the object's value--but we do not need to change the key (already set--used to find this value)
InnerList[intIndex] = objValue;
}
/// <summary>
/// Get the value associated with the supplied key.
/// </summary>
/// <param name="objKey">A key associated with the value to be returned.</param>
/// <returns>Returns the object associated with the key (can be null!). Returns null (Nothing in VB.NET) upon failure.</returns>
public virtual object GetValue ( object objKey )
{
// try to find the key in the key array
int intIndex = Keys.IndexOf(objKey);
// if the key was found, then we return its value
if ( intIndex != -1 )
{
// return the element's value (could be another associative array, but that's neither
// here nor there)
return List[intIndex];
}
// the key was not found
return null;
}
/// <summary>
/// Get the value associated with the supplied zero-based index.
/// </summary>
/// <param name="intIndex">The zero-based index of the element to return.</param>
/// <returns>Returns the element. Returns null (Nothing in VB.NET) upon failure.</returns>
public virtual object GetValue ( int intIndex )
{
// if the index exists, then we return its value
if ( intIndex > -1 && intIndex < Count )
{
// return the element's value (could be another associative array, but that's neither
// here nor there)
return List[intIndex];
}
// the index was out of bounds
return null;
}
/// <summary>
/// Get the key associated with the element at the specified zero-based index.
/// </summary>
/// <param name="intIndex">The zero-based index of the element to return.</param>
/// <returns>Returns the element's key. Returns null (Nothing in VB.NET) upon failure.</returns>
public virtual object GetKey ( int intIndex )
{
// if the index exists, then we return its value
if ( intIndex > -1 && intIndex < Count )
{
// return the element's key
return Keys[intIndex];
}
// the index was out of bounds
return null;
}
/// <summary>
/// Clear the associative array.
/// </summary>
public new virtual void Clear()
{
// remove the items from the base
base.Clear();
// remove all keys associated with the items
Keys.Clear();
}
/// <summary>
/// Removes the element specified in the associative array by the key.
/// </summary>
/// <param name="objKey">The key of the element to remove.</param>
public virtual void RemoveByKey ( object objKey )
{
// try to find the key in the key array, and then remove it
RemoveAt(Keys.IndexOf(objKey));
}
/// <summary>
/// Removes the element specified in the associative array of the object.
///
/// This will only find and remove the first occurrance of the object.
/// </summary>
/// <param name="objValue">The value to search for and remove.</param>
public virtual void Remove ( object objValue )
{
// try to find the key in the key array, and then remove it
RemoveAt(List.IndexOf(objValue));
}
/// <summary>
/// Removes the element specified in the associative array by the index (note: does NOT check keys).
/// </summary>
/// <param name="intIndex">The zero-based index of the element to remove.</param>
public new virtual void RemoveAt ( int intIndex )
{
// if the index exists, then remove it from the list (and its key)
if ( intIndex > -1 && intIndex < Count )
{
// remove the value
base.RemoveAt(intIndex);
// remove the associated key
Keys.RemoveAt(intIndex);
}
}
/// <summary>
/// Get the keys to the associative array (in order).
///
/// If there are no keys (Count == 0), then the returned array will be null (Nothing in VB.NET).
/// </summary>
public object []ArrayKeys
{
get
{
// used to allocate object array of all keys to
object[] objKeys = null;
// avoid returning an empty (0) array; return null instead
if ( Count != 0 )
{
// allocate enough space for the keys
objKeys = new object[Count];
// get a copy of the object array
Keys.CopyTo(objKeys);
// return the keys
return objKeys;
}
// there were no keys to return
return null;
}
}
/// <summary>
/// Initializes the Associative array.
/// </summary>
public AssociativeArray ( ) : base()
{
// init the key array as well
m_alKeys = new ArrayList();
}
/// <summary>
/// Initializes the Associative array, and defaults the list size to the supplied Capacity.
/// </summary>
/// <param name="intCapacity">The default size to initialize the list.</param>
public AssociativeArray ( int intCapacity ) : base(intCapacity)
{
// init the key array to the same size as the value list
m_alKeys = new ArrayList(intCapacity);
}
/// <summary>
/// Returns an enumerator that iterates through the associative array using a DictionaryEntry object.
/// </summary>
/// <returns>An instantiated AssociativeArrayEnumerator representing the current object.</returns>
public new virtual IDictionaryEnumerator GetEnumerator()
{
return new AssociativeArrayEnumerator(Keys, List);
}
/// <summary>
/// An enumerator used with the Associative Array class allowing for dictionary entry enumeration across the array.
/// </summary>
protected class AssociativeArrayEnumerator : IDictionaryEnumerator
{
/// <summary>
/// The index value used to reset/start the enumerator at.
/// </summary>
const int InitializeIndex = -1;
/// <summary>
/// The dictionary
/// </summary>
protected DictionaryEntry []m_deItems = null;
/// <summary>
/// The index of the current Dictionary Entry. Initialized as -1 because MoveNext puts it at 0 to begin with.
/// </summary>
protected int m_intIndex = InitializeIndex;
/// <summary>
/// Do not use.
/// </summary>
private AssociativeArrayEnumerator() { }
/// <summary>
/// Neither parameter should be null (Nothing in VB.NET) and both arrays should be the same length.
///
/// In the event that one array is shorter, than that arrays length is assumed for both.
/// </summary>
/// <param name="listKeys">The IList of keys for the associative array.</param>
/// <param name="listValues">The IList of values for the associative array.</param>
public AssociativeArrayEnumerator ( IList listKeys, IList listValues )
{
// used in loop
int i;
// if either array is null, then the size is set to 0
// if neither array is null, then the shorter Length is used (if they're equal, then the length is the same for both)
int intSize = (listKeys != null && listValues != null) ?
(listKeys.Count < listValues.Count ? listKeys.Count : listValues.Count) : 0;
// for valid lists, instantiate the dictionary entry array
if ( intSize != 0 )
{
// initialize the list to the proper size
m_deItems = new DictionaryEntry[intSize];
// loop through and add every entry
for ( i = 0; i < intSize; ++i )
{
// create new objects for every entry
m_deItems[i] = new DictionaryEntry(listKeys[i], listValues[i]);
}
}
}
/// <summary>
/// Get the selected Dictionary Entry.
/// </summary>
/// <param name="intIndex">A zero-based index to select the dictionary entry.</param>
/// <returns>Returns the selected Dictionary Entry, or null (Nothing in VB.NET) upon failure.</returns>
protected DictionaryEntry this [ int intIndex ]
{
get { return m_deItems[intIndex]; }
}
/// <summary>
/// Get/set the zero-based index associated with this enumerator.
/// </summary>
protected int Index
{
get { return m_intIndex; }
set { m_intIndex = value; }
}
/// <summary>
/// Validate the index before attempting to return an entry.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the index is out of range.</exception>
protected void ValidateIndex ( )
{
// make sure the index is a valid index (only use when trying to return an entry)
if ( m_deItems == null || Index < 0 || Index >= m_deItems.Length )
{
// alert the programmer that something is wrong
// only likely to happen with hand coded enumerator usage, not For Each usage
throw new InvalidOperationException("The enumerator's index is before or after the collection.");
}
}
/// <summary>
/// Get the current Dictionary Entry. Validates the index.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the index is out of range.</exception>
public DictionaryEntry Entry
{
get { ValidateIndex(); return this[Index]; }
}
/// <summary>
/// Get the current Dictionary Entry's key. Validates the index.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the index is out of range.</exception>
public object Key
{
get { return Entry.Key; }
}
/// <summary>
/// Get the current Dictionary Entry's value. Validates the index.
/// </summary>
/// <exception cref="System.InvalidOperationException">Thrown if the index is out of range.</exception>
public object Value
{
get { return Entry.Value; }
}
/// <summary>
/// Get the current Dictionary Entry.
/// </summary>
public object Current
{
get { return Entry; }
}
/// <summary>
/// Iterates to the next dictionary entry, and returns success or failure.
/// </summary>
/// <returns>Returns true if there are items left (Current is valid). Returns false if the end of the list has been reached (Current with throw an exception).</returns>
public bool MoveNext ( )
{
// iterate to the next index, and return whether the result is within the range of the dictionary entries array
return m_deItems != null && ++Index < m_deItems.Length;
}
/// <summary>
/// Reset the enumerator.
/// </summary>
public void Reset ( )
{
// reinit the index
Index = InitializeIndex;
}
}
/// <summary>
/// Checks to see if a key exists.
/// </summary>
/// <param name="objKey">The key to check for existance in the key collection.</param>
/// <returns>Returns true if the key exists in the current associative array (does not check sub-levels). Returns false otherwise.</returns>
public bool Contains ( object objKey )
{
// use the existing Keys method
return Keys.Contains(objKey);
}
/// <summary>
/// The associative array class does not currently support ReadOnly and FixedSize lists.
/// </summary>
public bool IsFixedSize
{
get { return false; }
}
/// <summary>
/// The associative array class does not currently support ReadOnly and FixedSize lists.
/// </summary>
public bool IsReadOnly
{
get { return false; }
}
/// <summary>
/// An array list of the keys associated in the associative array.
/// </summary>
ICollection IDictionary.Keys
{
get { return Keys; }
}
/// <summary>
/// An array list of the values associated in the associative array.
/// </summary>
public ICollection Values
{
get { return List; }
}
/// <summary>
/// Copies the list of values from the associative array to the specified array.
/// </summary>
/// <param name="aArray">The specified array must have zero-based indexing.</param>
/// <param name="intIndex">The zero-based index in array at which copying begins.</param>
public virtual void CopyTo(Array aArray, int intIndex)
{
// copy the data from the VALUES list to the array
List.CopyTo(aArray, intIndex);
}
/// <summary>
/// Get if the associative array is synchronized for threads. Possible inheriting classes may provide a Synchronized method.
/// </summary>
public virtual bool IsSynchronized
{
get { return false; }
}
/// <summary>
/// Get a syncronization object for this associative array.
///
/// In the event that you want to Synchronize this object for thread safety, then they need to lock the sync root before performing actions.
///
/// Unfortunately, the Synchronization only applies to THIS level of the associative array, but at the same time that is not a problem either because you should only be locking what you're using.
/// </summary>
public virtual object SyncRoot
{
get
{
// if it has not been created yet (the sync root to lock)
if ( m_objSyncRoot == null )
{
// safely create an object to lock
System.Threading.Interlocked.CompareExchange(ref this.m_objSyncRoot, new object(), null);
}
// return the sync root (created)
return m_objSyncRoot;
}
}
}
}
Here's an example usage of the above class:
using System;
using System.Text;
namespace AssociativeArray
{
class Program
{
static void Main(string[] args)
{
// create the test array
AssociativeArray aaTestArray = new AssociativeArray();
// test the value
aaTestArray["1", "2", "3", "4", "5"] = "five";
// test the value
aaTestArray["1", "2", "3", "4", "6"] = "six";
// test the value
aaTestArray["1", "2", "3", "4", "7"] = "seven";
// empty array
aaTestArray["1", "2", "4"] = new AssociativeArray();
//
aaTestArray['1', '2', '3', '4', '5'] = "not the same five";
//
aaTestArray[1, 2, 3, 4, 5] = "note the first array it uses is the one created by the character \'1\'";
aaTestArray[1, 2, 3, 4, 1] = 321.3D;
aaTestArray[1, 2, 3, 4, 2] = 342L;
aaTestArray[1, null] = UriFormat.Unescaped;
// try displaying the value
Console.WriteLine(Walk(aaTestArray));
aaTestArray.RemoveAt(1);
Console.WriteLine(Walk(aaTestArray));
Console.WriteLine(Walk(aaTestArray["1", "2", "3", "4", "6"]));
aaTestArray["1", "2", "3"] = null;
aaTestArray["2"] = null;
Console.WriteLine(Walk(aaTestArray));
Console.ReadLine();
}
static string Walk(object objTemp)
{
return Walk(objTemp, 0);
}
static string Walk(object objTemp, int intTabs)
{
StringBuilder sbTemp = new StringBuilder();
AssociativeArray aaArray = objTemp as AssociativeArray;
if ( aaArray != null )
{
//
sbTemp.Append("Array [Count = ").Append(aaArray.Count).Append(']').Append(Environment.NewLine);
sbTemp.Append("".PadLeft(intTabs, '\t')).Append('{').Append(Environment.NewLine);
//
foreach ( System.Collections.DictionaryEntry deEntry in aaArray )
{
sbTemp.Append("".PadLeft(intTabs + 1, '\t')).Append('[').Append(deEntry.Key == null ? "null" : deEntry.Key.ToString()).Append("] => ");
if ( deEntry.Value is AssociativeArray )
{
sbTemp.Append(Walk(deEntry.Value, intTabs + 1));
}
else
{
sbTemp.Append('\'').Append(deEntry.Value).Append("\' (Type: ").Append(deEntry.Value != null ? deEntry.Value.GetType().ToString() : "null").Append(')');
}
sbTemp.Append(Environment.NewLine);
}
sbTemp.Append("".PadLeft(intTabs, '\t')).Append('}').Append(Environment.NewLine);
}
else if ( objTemp != null )
return objTemp.ToString();
return sbTemp.ToString().Trim();
}
}
}
Picky |
|
| |
Free Download:
Books: LUCAS Associative Array Processor: Design, Programming, and Application Studies Authors: Christer Fernstrom, Ivan Kruzela, Bertil Svensson, Pages: 323, Published: 1986 PHP and MySQL Web Development Authors: Luke Welling, Laura Thomson, Pages: 871, Published: 2003 The Book of JavaScript: A Practical Guide to Interactive Web Pages Authors: Thau, Pages: 490, Published: 2007 PHP 5/MySQL Programming for the Absolute Beginner: No Experience Required Authors: Andy Harris, Pages: 464, Published: 2004 PHP Cookbook Authors: David Sklar, Adam Trachtenberg, Safari Tech Books Online, Pages: 608, Published: 2003 JavaScript: A Beginner's Guide Authors: John Pollock, Pages: 550, Published: 2004 Sams Teach Yourself PHP in 24 Hours: Php in 24 Hours Authors: Matt Zandstra, Pages: 550, Published: 2004 A practical guide to Unix for Mac OS X users Authors: Mark G. Sobell, Peter Seebach, Pages: 999, Published: 2006 UNIX: The Complete Reference Authors: Kenneth H. Rosen, Douglas A. Host, Richard R. Rosinski, James Farber, Pages: 1302, Published: 1999 Web:Associative array - Wikipedia, the free encyclopedia An associative array (also associative container, map, mapping, hash, dictionary , finite map, and in query-processing an index or index file) is an abstract ... PHP Tutorial - Array Learn the intricacies of PHP Arrays and how to use an associative array with Tizag.com's PHP Array lesson. Perl tutorial: Associative arrays To define an associative array we use the usual parenthesis notation, but the array itself is prefixed by a % sign. Suppose we want to create an array of ... JavaScript Associative Arrays Using associative arrays in javascript. ... Using associative arrays, you can call the array element you need using a string rather than a number, ... #464952 - ITP: wb -- disk-based associative array library for C ... Feb 10, 2008 ... Multiple associative arrays can reside in one disk file. Simultaneous access to multiple disk files is supported. A structure checking and ... Picking Up Perl - Associative Arrays (Hashes) This chapter will introduce the third major Perl abstract data type, associative arrays. Also known as hashes, associative arrays provide native language ... Associative Arrays in Oracle PL/SQL: Introduction Mar 13, 2006 ... An “Associative Array” can hold a huge amount of information in ... A typical “ Associative Array” in PL/SQL could be declared like this: ... JavaScript - Objects as associative arrays On this page I explain how JavaScript objects are also associative arrays ( hashes). Using these you can associate a key string with a value string, ... associative array Definition of associative array, possibly with links to more information and implementations. Perl Basics: Associative Arrays An introduction to the basics of Perl associative arrays. Videos: PHP Associative Array PHP Video tutorial, Arabic
PHP Associative Array C#/Xna - Dictionary As Associative Array For a high-res version please visit www.3dbuzz.com. This is part of a video helpfile that is constantly updated on www.3dbuzz.com. Don't worry the hi... PHP Tutorial - 11 - Associative Arrays visit www.thenewboston.com for all my tutorials! php learners - tutorial-11 - Associative Arrays http://phplearners.com/video-tutorial11.php
This tutorial shows how associative arrays work in the php language.
goto http://www.phplearners.com f... PHP Course 5-4 Associative Arrays pt. 2 PHP Course 5-3 Associative Arrays pt. 1 |
|
Search This Site:
|
|