How to sort an array of strings?

How to sort an array of strings?

Anonymous
Not applicable
1,411 Views
13 Replies
Message 1 of 14

How to sort an array of strings?

Anonymous
Not applicable
Hi,

I'm doing another arx training, now is about to have a function to return
all the layer names, but I want the output to be sorted, this is what I
have so far:

static addStringToRB (resbuf **work, const char *strVal)
{
resbuf *ptrNewbuf, *ptrPos;

ptrNewbuf = ptrPos = NULL;
ptrPos = *work;
*work = ptrPos;

if (*work)
{
while (ptrPos->rbnext != NULL)
ptrPos = ptrPos->rbnext;
}

if ((ptrNewbuf = acutNewRb(RTSTR)) == NULL)
{
acutPrintf("\nERROR: Unable to allocate memory for resbuf pointer.");
return FALSE;
}

if ((ptrNewbuf->resval.rstring = strdup(strVal)) == NULL)
{
acutPrintf("\nERROR: Unable to duplicate definition in memory.");
acutRelRb(ptrNewbuf);
return FALSE;
}

if (*work)
{
ptrPos->rbnext = ptrNewbuf;
ptrPos = ptrNewbuf;
}

else *work = ptrPos = ptrNewbuf;

return TRUE;
}

static int ads_getlayers(void)
{

resbuf *IsList = NULL;

AcDbLayerTable* pLayerTbl = NULL;


acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pLayerTbl,
AcDb::kForRead);

AcDbLayerTableIterator* pLayerIterator;
pLayerTbl->newIterator(pLayerIterator);

AcDbLayerTableRecord* pLayerTblRcd;
char *pLName;

// start iterator - not done
for(pLayerIterator->start() ; !pLayerIterator->done() ;
pLayerIterator->step()) {

//for (; !pLayerIterator->done(); pLayerIterator->step()) {

pLayerIterator->getRecord(pLayerTblRcd, AcDb::kForRead);
pLayerTblRcd->getName(pLName);
pLayerTblRcd->close();
//acutPrintf("\nLayer name: %s",pLName);

// adding the layer name into the list
addStringToRB(&IsList, pLName);

// deallocates the memory pointed to by pLName and sets pLName to NULL
acutDelString(pLName);
}

// delete the layer iterator
delete pLayerIterator;
// closing the layer table
pLayerTbl->close();

// if the list is empty [nil] return nil
if (IsList == NULL) acedRetNil();
// if not empty return the result-buffer

    and release the memory of the resbuf
    else {
    acedRetList(IsList);
    acutRelRb(IsList);
    }


    // return the layer list
    return (RSRSLT) ;
    }

    Now what I'm supposed to use in order to have the list of layers [strings]
    sorted? I have read about using the following:

    //Make a list.
    std::vector<:STRING> mylist;

    // then inside of the for...
    mylist.push_back(pLName);

    // Sort the list.
    std::sort(mylist.begin(), mylist.end());

    But I cannot figure out how to return "mylist" sorted.....

    If anyone could help me, please?

    Thanks,
    Luis.
0 Likes
1,412 Views
13 Replies
Replies (13)
Message 2 of 14

Anonymous
Not applicable
Luis Esquivel wrote:
> Hi,
>
> I'm doing another arx training, now is about to have a function to return
> all the layer names, but I want the output to be sorted, this is what I
> have so far:
>
> static addStringToRB (resbuf **work, const char *strVal)
> {
> resbuf *ptrNewbuf, *ptrPos;
>
> ptrNewbuf = ptrPos = NULL;
> ptrPos = *work;
> *work = ptrPos;
>
> if (*work)
> {
> while (ptrPos->rbnext != NULL)
> ptrPos = ptrPos->rbnext;
> }
>
> if ((ptrNewbuf = acutNewRb(RTSTR)) == NULL)
> {
> acutPrintf("\nERROR: Unable to allocate memory for resbuf pointer.");
> return FALSE;
> }
>
> if ((ptrNewbuf->resval.rstring = strdup(strVal)) == NULL)
> {
> acutPrintf("\nERROR: Unable to duplicate definition in memory.");
> acutRelRb(ptrNewbuf);
> return FALSE;
> }
>
> if (*work)
> {
> ptrPos->rbnext = ptrNewbuf;
> ptrPos = ptrNewbuf;
> }
>
> else *work = ptrPos = ptrNewbuf;
>
> return TRUE;
> }
>
> static int ads_getlayers(void)
> {
>
> resbuf *IsList = NULL;
>
> AcDbLayerTable* pLayerTbl = NULL;
>
>
> acdbHostApplicationServices()->workingDatabase()->getSymbolTable(pLayerTbl,
> AcDb::kForRead);
>
> AcDbLayerTableIterator* pLayerIterator;
> pLayerTbl->newIterator(pLayerIterator);
>
> AcDbLayerTableRecord* pLayerTblRcd;
> char *pLName;
>
> // start iterator - not done
> for(pLayerIterator->start() ; !pLayerIterator->done() ;
> pLayerIterator->step()) {
>
> //for (; !pLayerIterator->done(); pLayerIterator->step()) {
>
> pLayerIterator->getRecord(pLayerTblRcd, AcDb::kForRead);
> pLayerTblRcd->getName(pLName);
> pLayerTblRcd->close();
> //acutPrintf("\nLayer name: %s",pLName);
>
> // adding the layer name into the list
> addStringToRB(&IsList, pLName);
>
> // deallocates the memory pointed to by pLName and sets pLName to NULL
> acutDelString(pLName);
> }
>
> // delete the layer iterator
> delete pLayerIterator;
> // closing the layer table
> pLayerTbl->close();
>
> // if the list is empty [nil] return nil
> if (IsList == NULL) acedRetNil();
> // if not empty return the result-buffer

    > and release the memory of the resbuf
    > else {
    > acedRetList(IsList);
    > acutRelRb(IsList);
    > }
    >
    >
    > // return the layer list
    > return (RSRSLT) ;
    > }
    >
    > Now what I'm supposed to use in order to have the list of layers [strings]
    > sorted? I have read about using the following:
    >
    > //Make a list.
    > std::vector<:STRING> mylist;
    >
    > // then inside of the for...
    > mylist.push_back(pLName);
    >
    > // Sort the list.
    > std::sort(mylist.begin(), mylist.end());
    >
    > But I cannot figure out how to return "mylist" sorted.....
    >
    > If anyone could help me, please?
    >
    > Thanks,
    > Luis.

    Luis,

    You're on the right track. Iterate the sorted vector and call your
    addStringToRB() from the vector iterator loop instead of the layer table
    iterator loop:

    std::vector<:STRING>::iterator layer_iter;
    for(layer_iter = mylist.begin(); layer_iter != mylist.end(); layer_iter++)
    {
    addStringToRB(&IsList, layer_iter->c_str());
    }

    --
    Best regards,

    Byron Blattel
    CADwerx--Applications for AutoCAD
    Autodesk Registered Developer
    Contact Info @ http://www.cadwerx.net
    Custom Programming Services - ObjectARX/C++/MFC/ASP/STL/ATL/ISAPI...
0 Likes
Message 3 of 14

Anonymous
Not applicable
Thank you Byron,

Now, how can I incorporate the predicate function for the std:sort call?

For now I only have:

std::sort(mylist.begin(), mylist.end());



Thanks,

Luis.
0 Likes
Message 4 of 14

Anonymous
Not applicable
I have tried the following:

struct LessThan {

bool operator() (const std::string &a, const std::string &b) {return a < b;}

};



// Sort the list.

std::sort(mylist.begin(), mylist.end(), LessThan());


And I get the list like:

Command: (allayers)
("-fill-shade" "-fill-shade3" "0" "1" "11" "2" "3" "4" "5" "6" "7"
"A-DOOR-BLOCK-PLAN" "A-DOOR-PLAN" "A-DOOR-SWING-ELEV" "A-DOOR-SWING-PLAN"
"A-FRAME" "A-WALLS" "A-WIN-BLOCK-PLAN-DEMO" "A-WIN-BLOCK-PLAN-EXIST"
"A-WIN-BLOCK-PLAN-NEW" "A-WIN-FRAME-PLAN-DEMO" "A-WIN-FRAME-PLAN-EXIST"
"A-WIN-FRAME-PLAN-NEW" "A-WIN-PLAN" "A-WIN-PLAN-DEMO" "A-WIN-PLAN-EXIST"
"A-WIN-PLAN-NEW" "AR APPL SPEC" "AR APPLIANCE" "AR FIREPLACE" "CENTER"
"COUNTERTOP" "DASH_DOORS" "DEMO" "FIXTURES" "FLOOR_FINISH" "HIDDEN"
"ROOF_HIDDEN" "SIDING" "STAIRS" "STEEL_ROOF" "STONE_VENEER" "THRESHOLD"
"VIEWPORT")


Now, how can I do the sort for the numbers "0" "1" "2" "3" "4" "5" "6" "7"
"11".... not like it is right now:
"0" "1" "11" "2" "3" "4" "5" "6" "7"

Thanks.
Luis.

"Luis Esquivel" wrote in message
news:[email protected]...
Thank you Byron,

Now, how can I incorporate the predicate function for the std:sort call?

For now I only have:

std::sort(mylist.begin(), mylist.end());



Thanks,

Luis.
0 Likes
Message 5 of 14

Anonymous
Not applicable
Am I still in the right track? if so, can someone guide me into where I
should need to go to learn how to do a more complex sorting?... or give me a
hint, please?

Best regards,
Luis.
0 Likes
Message 6 of 14

Anonymous
Not applicable
Here, this is what I use. Note that it's a CStirngList instead of an array
of strings but the code is really straightforward:


/***** FUNCTION sortCStringList() *****/
void sortCStringList(CStringList *csListSort, BOOL bUp)
{

CStringList csListTemp;
CString csCompare, csTemp;
POSITION mPMin, mP, mPreP, mPTemp;

while(csListSort->GetCount() > 0) {

if(bUp) {
csCompare =
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
} else {
csCompare = "";
}

mP = csListSort->GetHeadPosition();

while(mP!=NULL) {
mPreP = mP;
csTemp = csListSort->GetNext(mP);
if((bUp && csCompare > csTemp) || (!bUp && csCompare < csTemp))
{
mPMin = mPreP;
csCompare = csTemp;
} /* endif */

} /* while mP */

csListTemp.AddTail(csListSort->GetAt(mPMin));
csListSort->RemoveAt(mPMin);

} /* while GetCount() */

mPTemp = csListTemp.GetHeadPosition();

while(mPTemp != NULL) {
csListSort->AddTail(csListTemp.GetNext(mPTemp));
}

} /* end of function sortCStringList() */




"Luis Esquivel" wrote in message
news:[email protected]...
Am I still in the right track? if so, can someone guide me into where I
should need to go to learn how to do a more complex sorting?... or give me a
hint, please?

Best regards,
Luis.
0 Likes
Message 7 of 14

Anonymous
Not applicable
Luis Esquivel wrote:
> I have tried the following:
>
> struct LessThan {
>
> bool operator() (const std::string &a, const std::string &b) {return a < b;}
>
> };

Something like this perhaps (I don't use std::string so there may be
some problems compiling but you should be able to get the logic)-

struct LessThan
{
bool operator()(const std::string &a, const std::string &b)
{
int numA = atoi(a);
int numB = atoi(b);
if(numA && numB) return numA < numB;
return a < b;
}
};


--
Best regards,

Byron Blattel
CADwerx--Applications for AutoCAD
Autodesk Registered Developer
Contact Info @ http://www.cadwerx.net
Custom Programming Services - ObjectARX/C++/MFC/ASP/STL/ATL/ISAPI...
0 Likes
Message 8 of 14

Anonymous
Not applicable
Thank you Byron;

But I have no idea on how to convert the std::string into integer.... 😞



struct LessThan
{
bool operator()(const std::string &a, const std::string &b)
{
int numA = atoi(a);
int numB = atoi(b);
if(numA && numB) return numA < numB;
return a < b;
}
};
0 Likes
Message 9 of 14

Anonymous
Not applicable
Let me ask you a mickey mouse question.... is there a way to convert the
array of strings into a CStringList or from the result-bufer [IsList in my
case]

Thanks.


"Ed DePaola" wrote in message
news:[email protected]...
Here, this is what I use. Note that it's a CStirngList instead of an array
of strings but the code is really straightforward:


/***** FUNCTION sortCStringList() *****/
void sortCStringList(CStringList *csListSort, BOOL bUp)
{

CStringList csListTemp;
CString csCompare, csTemp;
POSITION mPMin, mP, mPreP, mPTemp;

while(csListSort->GetCount() > 0) {

if(bUp) {
csCompare =
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
} else {
csCompare = "";
}

mP = csListSort->GetHeadPosition();

while(mP!=NULL) {
mPreP = mP;
csTemp = csListSort->GetNext(mP);
if((bUp && csCompare > csTemp) || (!bUp && csCompare < csTemp))
{
mPMin = mPreP;
csCompare = csTemp;
} /* endif */

} /* while mP */

csListTemp.AddTail(csListSort->GetAt(mPMin));
csListSort->RemoveAt(mPMin);

} /* while GetCount() */

mPTemp = csListTemp.GetHeadPosition();

while(mPTemp != NULL) {
csListSort->AddTail(csListTemp.GetNext(mPTemp));
}

} /* end of function sortCStringList() */




"Luis Esquivel" wrote in message
news:[email protected]...
Am I still in the right track? if so, can someone guide me into where I
should need to go to learn how to do a more complex sorting?... or give me a
hint, please?

Best regards,
Luis.
0 Likes
Message 10 of 14

Anonymous
Not applicable
Luis Esquivel wrote:
> Thank you Byron;
>
> But I have no idea on how to convert the std::string into integer.... 😞
>
>
>
> struct LessThan
> {
> bool operator()(const std::string &a, const std::string &b)
> {
> int numA = atoi(a);
> int numB = atoi(b);
> if(numA && numB) return numA < numB;
> return a < b;
> }
> };

You made me read up on std::string 🙂

struct LessThan
{
bool operator()(const std::string &a, const std::string &b)
{
int numA = atoi(a.c_str());
int numB = atoi(b.c_str());
if(numA && numB) return numA < numB;
return stricmp(a.c_str(), b.c_str()) < 0;
}
};

BTW, it's OK to struggle with this 🙂

--
Best regards,

Byron Blattel
CADwerx--Applications for AutoCAD
Autodesk Registered Developer
Contact Info @ http://www.cadwerx.net
Custom Programming Services - ObjectARX/C++/MFC/ASP/STL/ATL/ISAPI...
0 Likes
Message 11 of 14

Anonymous
Not applicable
NOOOOOOOO way.....

I found also the "c_str" but could not find how to implemented.... THANKS
Byron.

"Byron Blattel" wrote in message
news:[email protected]...
Luis Esquivel wrote:
> Thank you Byron;
>
> But I have no idea on how to convert the std::string into integer.... 😞
>
>
>
> struct LessThan
> {
> bool operator()(const std::string &a, const std::string &b)
> {
> int numA = atoi(a);
> int numB = atoi(b);
> if(numA && numB) return numA < numB;
> return a < b;
> }
> };

You made me read up on std::string 🙂

struct LessThan
{
bool operator()(const std::string &a, const std::string &b)
{
int numA = atoi(a.c_str());
int numB = atoi(b.c_str());
if(numA && numB) return numA < numB;
return stricmp(a.c_str(), b.c_str()) < 0;
}
};

BTW, it's OK to struggle with this 🙂

--
Best regards,

Byron Blattel
CADwerx--Applications for AutoCAD
Autodesk Registered Developer
Contact Info @ http://www.cadwerx.net
Custom Programming Services - ObjectARX/C++/MFC/ASP/STL/ATL/ISAPI...
0 Likes
Message 12 of 14

Anonymous
Not applicable
Now I see it..... it is returning the list sorted.

Command: (allayers)
("-fill-shade" "-fill-shade3" "0" "1" "2" "3" "4" "5" "6" "7" "11"
"A-DOOR-BLOCK-PLAN" "A-DOOR-PLAN" "A-DOOR-SWING-ELEV" "A-DOOR-SWING-PLAN"
"A-FRAME" "A-WALLS" "A-WIN-BLOCK-PLAN-DEMO" "A-WIN-BLOCK-PLAN-EXIST"
"A-WIN-BLOCK-PLAN-NEW" "A-WIN-FRAME-PLAN-DEMO" "A-WIN-FRAME-PLAN-EXIST"
"A-WIN-FRAME-PLAN-NEW" "A-WIN-PLAN" "A-WIN-PLAN-DEMO" "A-WIN-PLAN-EXIST"
"A-WIN-PLAN-NEW" "AR APPL SPEC" "AR APPLIANCE" "AR FIREPLACE" "CENTER"
"COUNTERTOP" "DASH_DOORS" "DEMO" "FIXTURES" "FLOOR_FINISH" "HIDDEN"
"ROOF_HIDDEN" "SIDING" "STAIRS" "STEEL_ROOF" "STONE_VENEER" "THRESHOLD"
"VIEWPORT")
0 Likes
Message 13 of 14

Anonymous
Not applicable
Ed,

I am still learning arx, let me understand first what a CSstringList is....
and I would implement your sample.

Best regards,
Luis.



"Ed DePaola" wrote in message
news:[email protected]...
Here, this is what I use. Note that it's a CStirngList instead of an array
of strings but the code is really straightforward:


/***** FUNCTION sortCStringList() *****/
void sortCStringList(CStringList *csListSort, BOOL bUp)
{

CStringList csListTemp;
CString csCompare, csTemp;
POSITION mPMin, mP, mPreP, mPTemp;

while(csListSort->GetCount() > 0) {

if(bUp) {
csCompare =
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
} else {
csCompare = "";
}

mP = csListSort->GetHeadPosition();

while(mP!=NULL) {
mPreP = mP;
csTemp = csListSort->GetNext(mP);
if((bUp && csCompare > csTemp) || (!bUp && csCompare < csTemp))
{
mPMin = mPreP;
csCompare = csTemp;
} /* endif */

} /* while mP */

csListTemp.AddTail(csListSort->GetAt(mPMin));
csListSort->RemoveAt(mPMin);

} /* while GetCount() */

mPTemp = csListTemp.GetHeadPosition();

while(mPTemp != NULL) {
csListSort->AddTail(csListTemp.GetNext(mPTemp));
}

} /* end of function sortCStringList() */




"Luis Esquivel" wrote in message
news:[email protected]...
Am I still in the right track? if so, can someone guide me into where I
should need to go to learn how to do a more complex sorting?... or give me a
hint, please?

Best regards,
Luis.
0 Likes
Message 14 of 14

Anonymous
Not applicable
Luis,

A CStringList is a basic MFC Class. You'll find everything you need in the
MFC Library. Basically, you loop through your data and use the .AddHead()
or .AddTail() class member to add elements to your list.

Try this in your layer iterator loop:

Add a variable (before the loop): CStringList myCSList;
Replace: "char *pLName" with "char chrLName[256]"; // sometimes I
have difficulties with char* in ARX
Replace: "addStringToRB(&IsList, pLName)" with
"myCSList.AddTail(chrLName)"

Now, after you've iterated through the layers, myCSList can be passed to the
function I gave you which will sort them alphabetically.

Read the MFC Class information and you'll see you can get the names from the
CStringList by using the .GetHead() or .GetTail() members.

Ed





"Luis Esquivel" wrote in message
news:[email protected]...
Ed,

I am still learning arx, let me understand first what a CSstringList is....
and I would implement your sample.

Best regards,
Luis.



"Ed DePaola" wrote in message
news:[email protected]...
Here, this is what I use. Note that it's a CStirngList instead of an array
of strings but the code is really straightforward:


/***** FUNCTION sortCStringList() *****/
void sortCStringList(CStringList *csListSort, BOOL bUp)
{

CStringList csListTemp;
CString csCompare, csTemp;
POSITION mPMin, mP, mPreP, mPTemp;

while(csListSort->GetCount() > 0) {

if(bUp) {
csCompare =
"ZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ";
} else {
csCompare = "";
}

mP = csListSort->GetHeadPosition();

while(mP!=NULL) {
mPreP = mP;
csTemp = csListSort->GetNext(mP);
if((bUp && csCompare > csTemp) || (!bUp && csCompare < csTemp))
{
mPMin = mPreP;
csCompare = csTemp;
} /* endif */

} /* while mP */

csListTemp.AddTail(csListSort->GetAt(mPMin));
csListSort->RemoveAt(mPMin);

} /* while GetCount() */

mPTemp = csListTemp.GetHeadPosition();

while(mPTemp != NULL) {
csListSort->AddTail(csListTemp.GetNext(mPTemp));
}

} /* end of function sortCStringList() */




"Luis Esquivel" wrote in message
news:[email protected]...
Am I still in the right track? if so, can someone guide me into where I
should need to go to learn how to do a more complex sorting?... or give me a
hint, please?

Best regards,
Luis.
0 Likes