[Closed] group faces by SetFaceColor
sorting an array of struct on a field wasn’t too tricky, but you have to move to using std::sort so you can pass the struct data index to the comparison routine
#include <algorithm>
struct float_compare
{
bool operator() (Value *a, Value *b)
{
return ((Struct*)a)->member_data[index]->to_float() < ((Struct*)b)->member_data[index]->to_float();
}
int index;
float_compare(int i) : index(i) {}
};
//********************************************************************************************
// usage
// sortsf <array of structs> <#struct_member_name>
Value* sortsf_cf(Value **arg_list, int count)
{
Array* theArray = (Array*)arg_list[0];
Struct* theStruct = (Struct*)theArray->data[0]; // use the first array element as the struct template
Value* temp;
// gets the member data index from the hash table, return undefined if not present
if((temp = theStruct->definition->get_member_value(arg_list[1])) == NULL)
return &undefined;
// create the sorting compare object with our index
// this is 1 based but I think max adds a dummy struct member at index 0 so it works
float_compare compare(temp->to_int());
// sort the array
std::sort(theArray->data, theArray->data + theArray->size, compare);
return Integer::intern(theArray->size);
}
the proof…
struct test
(
width,
height,
len
)
(
testarray = for i = 1 to 10 collect temp = test (random 0.0 10.0) (random 0.0 10.0) (random 0.0 10.0);
print testarray;
sortsf testarray #len;
format "
";
print testarray;
)
obviously it’s only test code but anyway enjoy
also adding
struct test
(
width,
height,
len
)
(
seed 0
ar3 = for k=1 to 100000 collect test (random -1.0 1.0) (random -1.0 1.0) (random -1.0 1.0)
gc()
t1 = timestamp()
m1 = heapfree
sortsf ar3 #len
format "sortsf >> t:% m:%
" (timestamp() - t1) (m1 - heapfree)
format " %
" (gethashvalue ar1 0)
)
to the testing script gives
sort >> t:78 m:68L
182459010
OK
qsortf >> t:47 m:68L
182459010
OK
sortsf >> t:125 m:68L
undefined
OK
so still pretty quick !
… and very cool!
i’ve extended your code trying to keep the style to support other ‘popular’ types:
struct float_compare
{
bool operator() (Value *a, Value *b)
{
return ((Struct*)a)->member_data[index]->to_float() < ((Struct*)b)->member_data[index]->to_float();
}
int index;
float_compare(int i) : index(i) {}
};
struct string_compare
{
bool operator() (Value *a, Value *b)
{
return ::_stricmp(((Struct*)a)->member_data[index]->to_string(),((Struct*)b)->member_data[index]->to_string()) < 0;
}
int index;
string_compare(int i) : index(i) {}
};
//*********************************************** ***************************************
// usage
// sortsp <array of structs> <#struct_member_name>
def_visible_primitive(sortsp, "sortsp");
Value* sortsp_cf(Value **arg_list, int count)
{
Array* theArray = (Array*)arg_list[0];
Struct* theStruct = (Struct*)theArray->data[0]; // use the first array element as the struct template
Value* temp;
// gets the member data index from the hash table, return undefined if not present
if((temp = theStruct->definition->get_member_value(arg_list[1])) == NULL) return &undefined;
int index = temp->to_int();
Value* value = theStruct->member_data[index];
// create the sorting compare object with our index
// this is 1 based but I think max adds a dummy struct member at index 0 so it works
if(is_float(value) || is_int(value) || is_time(value))
{
float_compare compare(index);
std::sort(theArray->data, theArray->data + theArray->size, compare);
}
else
if(is_string(value) || is_name(value))
{
string_compare compare(index);
std::sort(theArray->data, theArray->data + theArray->size, compare);
}
else return &undefined;
// sort the array
return Integer::intern(theArray->size);
}
nice I added a ascending/descending flag to my original (though I don’t really have any use at the moment for it, but it’s nice to learn a bit more about what goes on under hood). We should probably start a “proper” useful mxs extension functions thread as we have deviated quite a bit from the ops original topic. !
it would be possible to make it generic as per the mxs qsort but to do that you get the mxs function call Achilles heel so keeping the specific compare calls within the sdk is the way forward.
Hey denis, i was actually using the sort struct routine in earnest and discovered a smallish bug in the code. If you not noticed it yet heres the fix
change
Array* theArray = (Array*)arg_list[0];
to
Array* theArray = (Array*)arg_list[0];
if(theArray->size == 0) return Integer::intern(0);
you need bum out early if passed an empty array, no need for nasty mxs ** system exception **