Sort TList of structures

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Post Reply
mark_c
BCBJ Master
BCBJ Master
Posts: 244
Joined: Thu Jun 21, 2012 1:13 am

Sort TList of structures

Post by mark_c »

Hi,
I was thinking of using a TList to store several related bytes but: to reorder the list through the member of structure (e), how do you do it?

Code: Select all

void __fastcall TForm1::Button1Click(TObject *Sender)
{
        struct MyStruct
        {
                byte a;
                byte b;
                byte c;
                byte d;
                int e;
        };

        MyStruct *test = (struct MyStruct *) malloc(sizeof(struct MyStruct));
        TList *MyList = new TList;

        test->a=60;
        test->b=11;
        test->c=100;
        test->d=111;
        test->e=1500;
        MyList->Add(test);

        test->a=6;
        test->b=1;
        test->c=10;
        test->d=11;
        test->e=500;
        MyList->Add(test);

        free(test);
        delete MyList;
}
rlebeau
BCBJ Author
BCBJ Author
Posts: 1715
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Sort TList of structures

Post by rlebeau »

mark_c wrote:I was thinking of using a TList to store several related bytes but: to reorder the list through the member of structure (e), how do you do it?
Well, for starters, you are adding multiple pointers to the same MyStruct instance into the list. You are allocating only 1 MyStruct in memory, but you are modifying it multiple times. You need to allocate a separate MyStruct for each list entry. And if you are going to allocate dynamically you should be using 'new' instead of malloc().

Second, in order to sort structs in a TList, you need to use the TList::Sort() method, passing it a pointer to a custom sorting function.

Try something like this:

Code: Select all

struct MyStruct
{
    byte a;
    byte b;
    byte c;
    byte d;
    int e;
};

int __fastcall SortMyStructByE(void * Item1, void * Item2)
{
    MyStruct *myItem1 = (MyStruct*) Item1;
    MyStruct *myItem2 = (MyStruct*) Item2;

    // sort items as needed.  Return:
    // < 0 if Item1 goes before Item2
    // 0 if Item1 and Item2 are equal
    // > 0 if Item2 goes before Item1

    return myItem2->e - myItem1->e;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    TList *MyList = new TList;

    MyStruct *test = new MyStruct;
    test->a = 60;
    test->b = 11;
    test->c = 100;
    test->d = 111;
    test->e = 1500;
    MyList->Add(test);

    test = new MyStruct;
    test->a = 6;
    test->b = 1;
    test->c = 10;
    test->d = 11;
    test->e = 500;
    MyList->Add(test);

    MyList->Sort(&SortMyStructByE);

    // use MyList as needed...
    for(int i = 0; i < MyList->Count; ++i) {
        MyStruct *s = (MyStruct*) MyList->Items[i];
        Memo1->Lines->Add(s->e);
    }

    // cleanup
    for(int i = 0; i < MyList->Count; ++i) {
        delete (MyStruct*) MyList->Items[i];
    }
    delete MyList;
}
That being said, since you are using C++, consider using standard C++ containers and algorithms, such as std::vector and std::sort(). For example:

Code: Select all

#include <vector>
#include <algorithm>

struct MyStruct
{
    byte a;
    byte b;
    byte c;
    byte d;
    int e;
};

bool SortMyStructByE(const MyStruct &myItem1, const MyStruct &myItem2)
{
    // sort items as needed.  Return:
    // true if Item1 goes before Item2
    // otherwise false

    return myItem1.e < myItem2.e;
}

void __fastcall TForm1::Button1Click(TObject *Sender)
{
    std::vector<MyStruct> MyList;
    MyStruct test;

    test.a = 60;
    test.b = 11;
    test.c = 100;
    test.d = 111;
    test.e = 1500;
    MyList.push_back(test);

    test.a = 6;
    test.b = 1;
    test.c = 10;
    test.d = 11;
    test.e = 500;
    MyList.push_back(test);

    std::sort(MyList.begin(), MyList.end(), SortMyStructByE);

    // use MyList as needed...
    for(size_t i = 0; i < MyList.size(); ++i) {
        MyStruct &s = MyList[i];
        Memo1->Lines->Add(s.e);
    }

    // no manual cleanup needed...
}
Remy Lebeau (TeamB)
Lebeau Software
mark_c
BCBJ Master
BCBJ Master
Posts: 244
Joined: Thu Jun 21, 2012 1:13 am

Re: Sort TList of structures

Post by mark_c »

exceptional as always, thanks Remy
mark_c
BCBJ Master
BCBJ Master
Posts: 244
Joined: Thu Jun 21, 2012 1:13 am

Re: Sort TList of structures

Post by mark_c »

how do you reorder a list for (c) and (e)?
rlebeau
BCBJ Author
BCBJ Author
Posts: 1715
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA
Contact:

Re: Sort TList of structures

Post by rlebeau »

mark_c wrote:how do you reorder a list for (c) and (e)?
Simply adjust the code inside the sorting function as needed. Inside your function, you can do whatever you want, as long as it returns the proper return value. For example (using the TList/std::vector examples I provided earlier):

Code: Select all

int __fastcall SortMyStructByCandE(void * Item1, void * Item2)
{
    MyStruct *myItem1 = (MyStruct*) Item1;
    MyStruct *myItem2 = (MyStruct*) Item2;

    return (myItem1->c == myItem2->c)
        ? (myItem2->e - myItem1->e)
        : (int(myItem2->c) - int(myItem1->c));
}

MyList->Sort(&SortMyStructByCandE);

Code: Select all

bool SortMyStructByCandE(const MyStruct &myItem1, const MyStruct &myItem2)
{
    return (myItem1.c == myItem2.c)
        ? (myItem1.e < myItem2.e)
        : (myItem1.c < myItem2.c);

    /* alternatively:
    #include <tuple>
    return std::tie(myItem1.c, myItem1.e) < std::tie(myItem2.c, myItem2.e);
    */
}

std::sort(MyList.begin(), MyList.end(), SortMyStructByCandE);
Remy Lebeau (TeamB)
Lebeau Software
mark_c
BCBJ Master
BCBJ Master
Posts: 244
Joined: Thu Jun 21, 2012 1:13 am

Re: Sort TList of structures

Post by mark_c »

thanks Remy
Post Reply