TScriptArray Object
by James Ford · 07/17/2008 (9:24 am) · 16 comments
Download Code File
//------------------------------------------------------------------------------
// TScriptArray Resource
// Provided for free use by James C Ford
//
// Versions
//
// 1.2 July 26, 2008 Added reverse, getRandom, and sort
//
// 1.1 July 17, 2008 Added push_front, pop_front, and insert
//
// 1.0 July 15, 2008
//
//------------------------------------------------------------------------------
//
// Create and return a new TScriptArray object.
//
function TScriptArray::create()
{
%obj = new ScriptObject()
{
class = "TScriptArray";
elementCount = 0;
};
return %obj;
}
//
// Add a new element to the end of the array with the given value.
//
function TScriptArray::push_back( %this, %val )
{
%this.array[%this.elementCount] = %val;
%this.elementCount++;
}
//
// Remove the last element of the array and return its value.
//
function TScriptArray::pop_back( %this )
{
if ( %this.elementCount < 1 )
{
echo( "TScriptArray::pop_back, invalid with zero elements" );
return;
}
%val = %this.array[%this.elementCount - 1];
%this.array[%this.elementCount - 1] = "";
%this.elementCount--;
return %val;
}
//
// Add a new element to the front of the array with the given value,
// pushing all other elements back one in the array.
// Note that this is more expensive than push_back.
//
function TScriptArray::push_front( %this, %val )
{
for ( %i = %this.elementCount; %i > 0; %i-- )
{
%this.array[%i] = %this.array[%i-1];
}
%this.elementCount++;
%this.array[0] = %val;
}
//
// Remove the first element of the array and return its value.
// Preserves the order of all other elements in the array.
// Note that this is more expensive that pop_back.
//
function TScriptArray::pop_front( %this )
{
if ( %this.elementCount < 1 )
{
echo( "TScriptArray::pop_front, invalid with zero elements" );
return;
}
%val = %this.array[0];
for ( %i = 0; %i < %this.elementCount; %i++ )
{
%this.array[%i] = %this.array[%i+1];
}
// Not technically necessary to clear this,
// but protects against someone manipulating elementCount
%this.array[%this.elementCount-1] = "";
%this.elementCount--;
return %val;
}
//
// Insert a new element with the given value at the specified
// element index. The existing element at that index and all those
// after it will be pushed to the "right" one element in the array.
//
function TScriptArray::insert( %this, %idx, %val )
{
if ( %idx >= %this.elementCount )
{
echo( "TScriptArray::insert, " @ %idx @ " is outside of the array bounds" );
return;
}
for ( %i = %this.elementCount; %i > %idx; %i-- )
{
%this.array[%i] = %this.array[%i-1];
}
%this.elementCount++;
%this.array[%idx] = %val;
}
//
// Set the value of an existing element in the array.
//
function TScriptArray::set( %this, %idx, %val )
{
if ( %idx > %this.elementCount - 1 )
{
echo( "TScriptArray::setElement, " @ %idx @ " is outside of the array bounds" );
return;
}
%this.array[%idx] = %val;
}
//
// Return the value of an existing element in the array.
//
function TScriptArray::get( %this, %idx )
{
if ( %idx < 0 || %idx > %this.elementCount - 1 )
{
echo( "TScriptArray::getElement, " @ %idx @ " is outside of the array bounds" );
return;
}
return %this.array[%idx];
}
//
// Returns the number of elements in the array.
//
function TScriptArray::size( %this )
{
return %this.elementCount;
}
//
// Search for a value in the array and return the element
// index of the first occurance.
//
function TScriptArray::find( %this, %val )
{
for ( %i = 0; %i < %this.elementCount; %i++ )
{
if ( %this.array[%i] $= %val )
return %i;
}
return -1;
}
//
// Remove an element from the array and preserve order.
//
function TScriptArray::erase( %this, %idx )
{
if ( %idx > %this.elementCount - 1 )
{
echo( "TScriptArray::erase, " @ %idx @ " is outside of the array bounds" );
return;
}
%this.array[%idx] = "";
for ( %i = %idx; %i < %this.elementCount - 1; %i++ )
{
%this.array[%i] = %this.array[%i+1];
}
%this.elementCount--;
}
//
// Remove an element from the array faster, but does not
// preserve order. Copies the last element into the hole.
//
function TScriptArray::erase_fast( %this, %idx )
{
if ( %idx > %this.elementCount - 1 )
{
echo( "TScriptArray::erase_fast, " @ %idx @ " is outside of the array bounds" );
return;
}
%this.array[%idx] = "";
%this.array[%idx] = %this.array[%this.elementCount - 1];
%this.array[%this.elementCount - 1] = "";
%this.elementCount--;
}
//
// Print all array elements to the console.
//
function TScriptArray::print( %this )
{
echo( "---Printing ScriptArray---" );
if ( %this.elementCount == 0 )
echo( " [EMPTY]" );
for ( %i = 0; %i < %this.elementCount; %i++ )
{
echo( " element " @ %i @ ", " @ %this.array[%i] );
}
}
//
// Clears all array elements, setting the size to zero.
//
function TScriptArray::clear( %this )
{
// Clearing the strings is not really necessary,
// But is someone screws with the elementCount,
// it could be a good idea.
for ( %i = 0; %i < %this.elementCount; %i++ )
{
%this.array[%i] = "";
}
%this.elementCount = 0;
}
//
// Reverses the order of all elements in the array
//
function TScriptArray::reverse( %this )
{
%i = 0;
%j = %this.elementCount - 1;
while ( %i <= %j )
{
%temp = %this.array[%i];
%this.array[%i] = %this.array[%j];
%this.array[%j] = %temp;
%i++;
%j--;
}
}
//
// Returns the value of a random element in the array.
//
function TScriptArray::getRandom( %this )
{
if ( %this.elementCount == 0 )
{
error( "TScriptArray::getRandom, not valid with zero elements!" );
return;
}
%idx = getRandom( 0, %this.elementCount - 1 );
return %this.array[%idx];
}
//
// Sort the array using the passed comparison function.
//
// Example(s):
// $array.sort( "compareStrings", true );
// $array.sort( "compareDigits", true );
//
// %compare must be the name of a function you implement
// which takes two parameters and returns -1 if the first
// is less than the second, 1 if the first is greater than
// the second, and 0 if they are equal. Look below for
// examples that work for sorting strings and digits.
//
// Notes: this is is a bubble sort algorithm and is NOT
// suitable for a very large number of elements. Also if your
// comparison function does not return the proper values
// it CAN get stuck in an infinite loop.
//
function TScriptArray::sort( %this, %compare, %ascending )
{
if ( !isFunction( %compare ) )
{
error( "TScriptArray::sort, %compare is not a valid function!" );
return;
}
for ( %loop = true; %loop; )
{
%loop = false;
for ( %i = 0; %i < %this.elementCount - 1; %i++ )
{
%result = call( %compare, %this.array[%i], %this.array[%i+1] );
// The elements are equal
if ( %result == 0 )
continue;
// Swap the sign if necessary
if ( %ascending )
{
%result = (%result > 0) ? -1 : 1;
}
// Swap the elements
if ( %result < 0 )
{
%temp = %this.array[%i];
%this.array[%i] = %this.array[%i+1];
%this.array[%i+1] = %temp;
// We didn't make it through the list without a swap,
// so keep looping
%loop = true;
}
}
}
}
function compareStrings( %a, %b )
{
return strcmp( %a, %b );
}
function compareDigits( %a, %b )
{
return ( %a - %b );
}About the author
http://jamesdev.info
#2
07/15/2008 (6:06 pm)
Awesome! This could be very useful.
#3
07/17/2008 (8:12 pm)
Added push_front, pop_front, insert, and also uploaded it as a file.
#4
07/25/2008 (11:25 pm)
Added reverse, getRandom, and sort. Sort can be easily adapted to your use by writing a new comparison function (in script).
#5
07/29/2008 (12:46 am)
I didn't really mean to rate my own resource, well, I didn't think it would really work. Oops, at least I picked a 5!
#6
08/07/2008 (4:55 am)
wooow... its like a charm
#7
01/03/2009 (5:55 am)
Hi Everyone and thanks James for a very useful resource.
#8
02/18/2009 (11:13 am)
I'm a little unsure about what the proper method is of instantiating a new TScriptArray.%newArray = TScriptArray::create();Is that right?
#9
02/18/2009 (1:06 pm)
Yep, that is correct. Also don't forget to do %newArray.delete() when you are done with it, it will 'not' be deleted automatically when it goes out of scope.
#10
02/18/2009 (5:54 pm)
Thanks for the awesome resource James! I'd rate it a 5 but it seems that is not a possibility after the site relaunch. :-/
#11
02/26/2009 (6:09 pm)
Thanks for a great resource James ! Its exactly what I was looking for.
#12
- Tim
And also a string no case compare. Im not sure a one line function counts as writing but what the heck...
03/05/2009 (5:39 am)
For those who have a big array to search, I wrote a binary search for James' resource. Be sure your array is sorted from lowest value to highest or the binary search won't work. I hadn't written one of these in years. So, it was quite a geek moment for me :-)- Tim
//
// Binary Search for a value using the passed comparison function
// and return the index of the first occurance.
//
// Example(s):
// $array.find_binary( "compareStringsNocase", "hello" );
// $array.find_binary( "compareDigits", 123 );
//
// %compare must be the name of a function you implement
// which takes two parameters and returns -1 if the first
// is less than the second, 1 if the first is greater than
// the second, and 0 if they are equal. Look below for examples.
//
function TScriptArray::find_binary( %this, %compare, %val )
{
// set starting high and low values
%low = 0;
%high = %this.elementCount - 1;
// loop through the array
while (%low <= %high) {
// calculate the midpoint for this value
%mid = mFloor( %low + ( (%high - %low) / 2 ) );
// call compare function
%result = call( %compare, %this.array[%mid], %val );
// check if we are too hot or too cold or just right
if (%result > 0)
%high = %mid - 1; // too high
else if (%result < 0)
%low = %mid + 1; // too low
else
return %mid; // found
}
return -1; // not found
}And also a string no case compare. Im not sure a one line function counts as writing but what the heck...
function compareStringsNocase( %a, %b )
{
return stricmp( %a, %b );
}
#13
03/05/2009 (11:52 pm)
Whats with the weird naming conventions? what ever happend to pop, push, shift, and unshift
#14
03/06/2009 (9:38 am)
Are you referring to push/pop_front/back? I took that naming convention from the engine tVector class. What is shift/unshift the equivalent of?
#15
plain push & pop are only useful for a strict stack.
03/06/2009 (10:54 am)
push_front and push_back are totally sensible function names, imo.plain push & pop are only useful for a strict stack.

Associate James Ford
Sickhead Games
You can find the other ScriptArray resource Here.
I anyone would like to add additional methods, or would like me to, feel free to email me.
jamesf42[at]gmail