Array.SortRange()

BlitzMax Forums/BlitzMax Module Tweaks/Array.SortRange()

fredborg(Posted 2006) [#1]
Hi,

A small tweak so you can sort only part of an array. I find it useful, because it means you can pre-allocate a nice big array, even though you might not use all of it, and still sort it.

Normally you have to slice the array to contain only valid elements (ie. no Null references), if you want to sort it. This gets around that nice and easily.

The following changes are needed:

In mod/brl.mod/blitz.mod/blitz_array.h, after the bbArraySort line for instance, add:
void		bbArraySortRange( BBArray *arr,int lo,int hi,int ascending );
In mod/brl.mod/blitz.mod/blitz_array.c, after the bbArraySort line, add:
	bbArraySortRange,

And at the end of the file add:
void bbArraySortRange( BBArray *arr,int lo,int hi,int ascending ){
	void *p;
	if( (hi-lo)<=0 ) return;
	p=BBARRAYDATA(arr,arr->dims);
	if( ascending ){
		switch( arr->type[0] ){
		case 'b':qsort_b( (unsigned char*)p+lo,(unsigned char*)p+hi );break;
		case 's':qsort_s( (unsigned short*)p+lo,(unsigned short*)p+hi );break;
		case 'i':qsort_i( (int*)p+lo,(int*)p+hi );break;
		case 'l':qsort_l( (BBInt64*)p+lo,(BBInt64*)p+hi );break;
		case 'f':qsort_f( (float*)p+lo,(float*)p+hi );break;
		case 'd':qsort_d( (double*)p+lo,(double*)p+hi );break;
		case '$':case ':':qsort_obj( (BBObject**)p+lo,(BBObject**)p+hi );break;
		}
	}else{
		switch( arr->type[0] ){
		case 'b':qsort_b_d( (unsigned char*)p+lo,(unsigned char*)p+hi );break;
		case 's':qsort_s_d( (unsigned short*)p+lo,(unsigned short*)p+hi );break;
		case 'i':qsort_i_d( (int*)p+lo,(int*)p+hi );break;
		case 'l':qsort_l_d( (BBInt64*)p+lo,(BBInt64*)p+hi );break;
		case 'f':qsort_f_d( (float*)p+lo,(float*)p+hi );break;
		case 'd':qsort_d_d( (double*)p+lo,(double*)p+hi );break;
		case '$':case ':':qsort_obj_d( (BBObject**)p+lo,(BBObject**)p+hi );break;
		}
	}
}
In mod/brl.mod/blitz_classes.i, after the -Sort( ... ) line (at the end of the file), add:
	-SortRange( lo:Int,hi:Int,ascending=1 )="bbArraySortRange"
Now all you need to do is recompile your modules (Ctrl+D). You may need to modify blitz.mod in order for it to work, just open it, hit space somewhere and recompile the modules.

Here's a small example of the use of SortRange()
Local bob:Int[] = [9,8,7,6,5,4,3,2,1]

bob.SortRange(0,5)
For i = 0 Until bob.length
	Print bob[i]
Next
It takes three parameters:
lo = the first array index to start the sorting from
hi = the last array index to include in the sort
ascending = whether you want to sort hi->lo or lo->hi

If you use it like this bob.SortRange(0,bob.length-1) it sorts the entire array, just like the regular Sort method.

Here's a silly example showing how SortRange can come in handy:
Strict

Type whatever
	Field alpha
	
	Method compare:Int(other:Object)
		If Whatever(other)
			Return Sgn(alpha - Whatever(other).alpha)
		EndIf
		Return -1
	EndMethod
EndType

Local bob:Whatever[8]
For Local i:Int = 0 To 3
	bob[i] = New Whatever
	bob[i].alpha = Rand(0,6)
Next

bob.SortRange(0,3)

'
' This wouldn't work because the array has Null references
' bob.Sort()

For Local i:Int = 0 Until bob.length
	If bob[i]
		Print bob[i].alpha
	Else
		Print "Null"
	EndIf
Next
Hope you have a use for it!