new console functions: SortWords() and SortNumbers()
by Orion Elenzil · 11/25/2006 (10:00 pm) · 7 comments
i was a little surprised this wasn't already implemented. maybe they are in TGE 1.4 or 1.5.
this routines are funny, 100% of the work involved is really just converting from space-delimited args to arrays and back again. anyhow.
To implement, simply copy the following hunk of code to the bottom (or wherever) of consoleFunctions.cc
examples:
this routines are funny, 100% of the work involved is really just converting from space-delimited args to arrays and back again. anyhow.
[b]usage:[/b] SortWords (<space -delimited list of words >, [ignoreCase = true], [increasing = true]) SortFields (<tab -delimited list of words >, [ignoreCase = true], [increasing = true]) SortRecords(<newline -delimited list of words >, [ignoreCase = true], [increasing = true]) SortNumbers(<whitespace-delimited list of numbers>, [increasing = true]) note the difference between actual space (space) and whitespace (space, tab, cr or nl)
To implement, simply copy the following hunk of code to the bottom (or wherever) of consoleFunctions.cc
ConsoleFunctionGroupBegin( Sorting, "Functions for sorting words, numbers, etc.");
static bool sIgnoreCase;
static bool sIncreasing;
static S32 QSORT_CALLBACK qSortCallbackTextCompare(const void* a, const void* b)
{
StringTableEntry* ea = (StringTableEntry*)(a);
StringTableEntry* eb = (StringTableEntry*)(b);
S32 result;
if (sIgnoreCase)
result = dStricmp(*ea, *eb);
else
result = dStrcmp (*ea, *eb);
if (!sIncreasing)
result = -result;
return result;
}
static S32 QSORT_CALLBACK qSortCallbackFloatCompare(const void* a, const void* b)
{
float* ea = (float*)(a);
float* eb = (float*)(b);
S32 result;
// note we are comparing floats, and will *NEVER* return "equal".
result = (*ea < *eb) ? -1 : 1;
if (!sIncreasing)
result = -result;
return result;
}
const char* SortUnits(const char* units, bool ignoreCase, bool increasing, const char* delimiter)
{
sIgnoreCase = ignoreCase;
sIncreasing = increasing;
// extract the words
S32 numItems = getUnitCount(units, delimiter);
if (numItems < 2)
return units;
char** items = new char*[numItems];
for (S32 n = 0; n < numItems; n++)
{
const char* item = getUnit(units, n, delimiter);
items[n] = dStrdup(item);
}
// actually do some work
dQsort((void *)items, numItems, sizeof(*items), qSortCallbackTextCompare);
// put em into a return buffer
char *ret = Con::getReturnBuffer(dStrlen(units) + 1);
ret[0] = '[[6101dedd71226]]';
for (S32 n = 0; n < numItems; n++)
{
if (n > 0)
dStrcat(ret, delimiter);
dStrcat(ret, items[n]);
}
// free the array
for (S32 n = 0; n < numItems; n++)
dFree(items[n]);
delete [] items;
return ret;
}
ConsoleFunction(SortWords, const char *, 2, 4,"SortWords(words, [ignoreCase=true], [increasing=true])")
{
bool ignoreCase = true;
bool increasing = true;
if (argc > 2)
ignoreCase = dAtob(argv[2]);
if (argc > 3)
increasing = dAtob(argv[3]);
return SortUnits(argv[1], ignoreCase, increasing, " ");
}
ConsoleFunction(SortFields, const char *, 2, 4,"SortFields(words, [ignoreCase=true], [increasing=true])")
{
bool ignoreCase = true;
bool increasing = true;
if (argc > 2)
ignoreCase = dAtob(argv[2]);
if (argc > 3)
increasing = dAtob(argv[3]);
return SortUnits(argv[1], ignoreCase, increasing, "\t");
}
ConsoleFunction(SortRecords, const char *, 2, 4,"SortRecords(words, [ignoreCase=true], [increasing=true])")
{
bool ignoreCase = true;
bool increasing = true;
if (argc > 2)
ignoreCase = dAtob(argv[2]);
if (argc > 3)
increasing = dAtob(argv[3]);
return SortUnits(argv[1], ignoreCase, increasing, "\n\r");
}
ConsoleFunction(SortNumbers, const char *, 2, 4,"SortNumbers(numbers, [increasing=true])")
{
// extract the numbers as floats.
S32 numItems = getUnitCount(argv[1], " \t\n\r");
if (numItems < 2)
return argv[1];
F32* items = new F32[numItems];
for (S32 n = 0; n < numItems; n++)
{
const char* item = getUnit(argv[1], n, " \t\n\r");
items[n] = dAtof(item);
}
// get our optional arguments
if (argc > 2)
sIncreasing = dAtob(argv[2]);
else
sIncreasing = true;
// actually do some work
dQsort((void*)items, numItems, sizeof(*items), qSortCallbackFloatCompare);
// put em into a return buffer
char buf[16]; // should be enough room, neh ? 13 is the largest i see: "1.23456e+789 "
char *ret = Con::getReturnBuffer(numItems * sizeof(buf) + 1);
ret[0] = '[[6101dedd71226]]';
for (S32 n = 0; n < numItems; n++)
{
if (n > 0)
dSprintf(buf, sizeof(buf), " %g", items[n]);
else
dSprintf(buf, sizeof(buf), "%g" , items[n]);
dStrcat(ret, buf);
}
// free the array
delete [] items;
return ret;
}
ConsoleFunctionGroupEnd( Sorting );examples:
==>echo(SortWords("dog cat Orion mouse 100 37"));
100 37 cat dog mouse Orion
==>echo(SortWords("dog cat Orion mouse 100 37", false));
100 37 Orion cat dog mouse
==>echo(SortWords("dog cat Orion mouse 100 37", true, false));
Orion mouse dog cat 37 100
==>echo(SortNumbers("100 37 2.3 -2.3 -3.2"));
-3.2 -2.3 2.3 37 100
==>echo(SortNumbers("100 37 2.3 -2.3 -3.2", false));
100 37 2.3 -2.3 -3.2About the author
#2
11/27/2006 (6:25 am)
Very handy indeed :)
#3
will soon modify to accept a list of delimiters, with space, tab, and newline as defaults.
11/30/2006 (12:50 am)
realized this would be more useful if it weren't hardwired for space-delimited entries.will soon modify to accept a list of delimiters, with space, tab, and newline as defaults.
#5
03/02/2007 (5:01 pm)
expanded this to include SortFields() and SortRecords().
#7
error C3861: 'getUnitCount': identifier not found
error C3861: 'getUnit': identifier not found
error C3861: 'getUnitCount': identifier not found
The solution is to add a "StringUnit::" prior to each function call - so "StringUnit::getUnit(" etc.
Thanks to Alex Scarborough for this fix :)
08/06/2008 (4:34 pm)
I had some problems with TGB 1.7 with the following errors:error C3861: 'getUnitCount': identifier not found
error C3861: 'getUnit': identifier not found
error C3861: 'getUnitCount': identifier not found
The solution is to add a "StringUnit::" prior to each function call - so "StringUnit::getUnit(" etc.
Thanks to Alex Scarborough for this fix :)

Torque Owner Stefan Lundmark