Sort TList of structures

This is the forum for miscellaneous technical/programming questions.

Moderator: 2ffat

Sort TList of structures

Postby mark_c » Fri May 08, 2020 8:34 am

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;
}
mark_c
BCBJ Master
BCBJ Master
 
Posts: 234
Joined: Thu Jun 21, 2012 1:13 am

Re: Sort TList of structures

Postby rlebeau » Fri May 08, 2020 1:19 pm

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
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1674
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Sort TList of structures

Postby mark_c » Sat May 09, 2020 5:07 am

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

Re: Sort TList of structures

Postby mark_c » Mon May 11, 2020 12:17 pm

how do you reorder a list for (c) and (e)?
mark_c
BCBJ Master
BCBJ Master
 
Posts: 234
Joined: Thu Jun 21, 2012 1:13 am

Re: Sort TList of structures

Postby rlebeau » Mon May 11, 2020 2:16 pm

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
User avatar
rlebeau
BCBJ Author
BCBJ Author
 
Posts: 1674
Joined: Wed Jun 01, 2005 3:21 am
Location: California, USA

Re: Sort TList of structures

Postby mark_c » Tue May 12, 2020 12:42 pm

thanks Remy
mark_c
BCBJ Master
BCBJ Master
 
Posts: 234
Joined: Thu Jun 21, 2012 1:13 am


Return to Technical

Who is online

Users browsing this forum: Bing [Bot] and 20 guests