I have a problem with a sort I am trying to do with a std::vector. I am doing an example below where I push_back some strings like this.
I know I have to use a comparator for this, that I have called: "compare_on_asscending_value"

The problem is that I am not sure of the logic how to write this comparator.
The code below I use inside a buttoncontrol.
I am thinking of to substring the strings so I convert the beginning number into doubles and from here doing a comparator that look if OneNumber > SecondNumber etc...

So my question is how to write this comparator and I beleive I have to write this comparator outside the buttoncontrol ?

Below will show what sort I am after:

This is the sortresult now wich is wrong:
3.55,defg32
20.32,bc4
12.44,ffdasd34
-3.52,c4
-20.45,ab555
-12.44,es48

This is the sort I am after: (Ascending order(Higher->Lower) for the beginning numbers)
20.32,bc4
12.44,ffdasd34
3.55,defg32
-3.52,c4
-12.44,es48
-20.45,ab555

std::vector<string> Sorting;

std::string One = "-20.45,ab555";
std::string Two = "20.32,bc4";
std::string Three = "-3.52,c4";
std::string Four = "3.55,defg32";
std::string Five = "-12.44,es48";
std::string Six = "12.44,ffdasd34";

Sorting.push_back(One);
Sorting.push_back(Two);
Sorting.push_back(Three);
Sorting.push_back(Four);
Sorting.push_back(Five);
Sorting.push_back(Six);

std::sort( Sorting.rbegin(), Sorting.rend()/*, compare_on_asscending_value*/);

String^ ShowSort = "";
		 
for( int i = 0; i < 6; i++ )
{
       String^ ShowSort = gcnew String(Sorting[i].c_str());
       MessageBox::Show(ShowSort);
}

Recommended Answers

All 12 Replies

You need to write the comparitor.

#include <sstream>
#include <string>

struct mysort
  {
  bool operator () ( const std::string& a, const std::string& b )
    {
    std::stringstream as( a );
    std::stringstream bs( b );
    double ad, bd;
    as >> ad;
    bs >> bd;
    return ad < bd;
    }
  };

Now you can use it with the sort() algorithm.

#include <algorithm>
#include <vector>

...

int main()
  {
  using namespace std;

  vector<string> v;
  v.push_back( "3.1,there" );
  v.push_back( "-0.7,hello" );
  v.push_back( "10.0,friend" );
  v.push_back( "3.2,my" );

  sort( v.begin(), v.end(), mysort() );

  for (unsigned i = 0; i < v.size(); i++)
    cout << v[ i ] << endl;

  return 0;
  }

Hope this helps.

Thank you. I have to ask here, The first code is using a struct like: struct mysort

Is this possible to use when you are writing the other code inside a
buttoncontrol (Managed Area) ?
I had some problem with this before also.

The strings that are push_backed occur inside the buttoncontrol so I am not sure if I have to use private: or public: in any way for the struct.

Is this possible to use when you are writing the other code inside a
buttoncontrol (Managed Area) ?
I had some problem with this before also.

I think you should very well be capable of using code inside a button click handler i.e.

// inside a handler
 vector<string> v;
  v.push_back( "3.1,there" );
  v.push_back( "-0.7,hello" );
  v.push_back( "10.0,friend" );
  v.push_back( "3.2,my" );
  sort( v.begin(), v.end(), mysort() );

There is no need to change the struct mysort , i.e. have it like Duoas wrote it.

There is a few steps I am not sure if I understand. I think I will begin to ask about the code below.
If I first just put this code like this in my Form code, I will have an Errormessage that says:

'Form1::Form1::mysort' : a native type cannot be nested within a managed type 'Form1::Form1'

#include "stdafx.h"
#include <string>
#include <algorithm>
using namespace std;

		~Form1()
		{
			if (components)
			{
				delete components;
			}
		}

	protected: 

struct mysort
  {
  bool operator () ( const std::string& a, const std::string& b )
    {
    std::stringstream as( a );
    std::stringstream bs( b );
    double ad, bd;
    as >> ad;
    bs >> bd;
    return ad < bd;
    }
  };

'Form1::Form1::mysort' : a native type cannot be nested within a managed type 'Form1::Form1'

OK, now I understand what you meant in your previous post. The error means that you are not allowed to nest the (native c++) struct mysort inside the managed class.
To avoid that, simply define the struct mysort outside the Form1 class (and any other managed class for that matter), i.e.

#include "stdafx.h"
#include <string>
#include <algorithm>
using namespace std;

// the native C++ struct 
struct mysort
  {
  bool operator () ( const std::string& a, const std::string& b )
    {
    std::stringstream as( a );
    std::stringstream bs( b );
    double ad, bd;
    as >> ad;
    bs >> bd;
    return ad < bd;
    }
  };

// then the usual 'using ...' stuff ...
using namespace System;
using namespace System::ComponentModel;
using namespace System::Collections;
using namespace System::Windows::Forms;
// etc ...

// and then the Form1 class ...
public ref class Form1 : public System::Windows::Forms::Form
{
// rest of the Form1 class's code follows ...

CLR code doesn't like it if you stick your own types into something it wants to manipulate exclusively.

Just stick the struct definition somewhere else (outside the CLR class). It won't hurt anything...

Hope this helps... (hope that works, I've never played with .NET). If worse comes to worse, you can just convert it into a regular function:

bool mysort( const std::string&a, const std:string& b )
  {
  ...
  }

and call the sort with

std::sort( myvect.begin(), myvect.end(), mysort );

Hope this helps.

Ok, then I understand : ) Now I have put this struct in the correct place and it compiles fine.
Now I beleive my real question comes. I am not sure if I understand something here.
Now when I push_back things into a vector and are putting the 3:rd argument 'mysort' in the std::sort inside the buttoncontrol like the code below, I will have a compileerror that says:

'mysort' : illegal use of this type as an expression

I have a few wonderings here at the same time. I beleive that the sortstruct has to get the substrings from the Sorting vector that are inside the buttoncontrol.
I am not sure how this communication will work.
I am not sure what "a" and "b" represents in the struct code below.
I understand the conversion from string to double with stringstream.

My question it how the communication between the vector and the struct is working and what "a" and "b" represents.

struct mysort
  {
  bool operator () ( const std::string& a, const std::string& b )
    {
    std::stringstream as( a );
    std::stringstream bs( b );
    double ad, bd;
    as >> ad;
    bs >> bd;
    return ad < bd;
    }
  };
//Code that Sorting.push_back(Stuff);

std::sort( Sorting.rbegin(), Sorting.rend(), mysort);

This did compile though if this is correct to do when I changed mysort to mysort()

std::sort( Sorting.rbegin(), Sorting.rend(), mysort());

It seemed to work, when running the code the sort will be like this wich is correct:
(Ascending order for the beginning number)
20.32,bc4
12.44,ffdasd34
3.55,defg32
-3.52,c4
-12.44,es48
-20.45,ab555

So my question is how this is possible because the strings that I am sorting is not a double like this string, it is only strings. However it sorts everyting correct ?:
20.32,bc4

because the sortcomparator convert a string into a double and if it convert 20.32,bc4 into a double it wouldn´t be possible ?:

std::stringstream as( a );
    std::stringstream bs( b );
    double ad, bd;
    as >> ad;
    bs >> bd;
    return ad < bd;

have a compileerror that says:

'mysort' : illegal use of this type as an expression

You are missing the parenthesis there ... std::sort( Sorting.rbegin(), Sorting.rend(), mysort[B]()[/B]);

I have a few wonderings here at the same time. I beleive that the sortstruct has to get the substrings from the Sorting vector that are inside the buttoncontrol.
I am not sure how this communication will work.

The sort() algorithm calls the mysort's bool operator () ( ... ) to determine the sort order of the vector's strings. The communication is taken care by the sort() algorithm internally.

I am not sure what "a" and "b" represents in the struct code below.

They represent the individual strings whose relative order needs to be determined i.e. the strings that are stored in the vector being sorted. The sort() algorithm figures out which strings to pass in to the mysort's comparator (two at a time), the comparator just needs to tell the result (bool) of the comparison.

std::sort and functors
Things like std::sort() are template functions. They don't exist until you try to use them with a specific type.

What follows is functional programming concepts.

The sort algorithm takes as a third argument a binary predicate, which is a function taking two arguments and returning true or false.

In the case of the sort algorithm, the predicate returns true if the first argument is strictly less-than the second argument. For integers, such a predicate might look like:

bool int_pred( int a, int b )
  {
  return (a < b);
  }

And you can sort a list of integers with it:

// This code assumes you compile with writable constants.
int ints[ 6 ] = { 1, -7, 54, 12, 519, 42 };
sort( ints, ints +6, int_pred );

The predicate need not be an actual function (like int_pred()). It can be a function object, or what is commonly called a functor.
An int_pred functor looks much the same as the function did:

struct int_pred2
  {
  bool operator () ( int a, int b )
    {
    return (a < b);
    }
  };

The only difference now is that the function is wrapped up into an object type (or class), with the () operator properly overloaded. You could use it normally, except that you must first instantiate an object of type int_pred2 before you can use it.

if (int_pred( 10, 20 )) cout << "yeah!\n";
if (int_pred2()( 10, 20 )) cout << "yeah!\n";

//same code as before
int ints[ 6 ] = { 1, -7, 54, 12, 519, 42 };
sort( ints, ints +6, int_pred2() );  // <-- see following comments

In the first example, the predicate was actually a function (well, the address of a function). In this example, the predicate is a functor --which is an object. Hence the presence of the () at the end of its name, since we are creating a new object. We could just as easily have written:

int_pred2 p;
...
sort( ints, ints +6, p );

Since p is already an instantiated object this works just as you'd expect.

funky string comparisons
As for your second question, let's examine how the two strings are compared.
The predicate gets two strings, a and b, and needs to return whether a is strictly less-than b.

However, you want to sort on the meaning of only part of the content of the string. This necessitates doing some manipulations first. And string manipulations are the specialty of stringstreams.

stringstream as( a );  // turn 'a' into an istream named 'as'
stringstream bs( b );  // turn 'b' into an istream named 'bs'

Now we can treat as and bs as any other istream and extract out the representation of a double at the beginning of the string into an actual double:

double ad; as >> ad;  // in a sense, cin >> mydoublevar, that is,
double bd; bs >> bd;  // extract the double. Extraction stops with
                      // the first invalid character in the istreams.

Finally, we have two doubles that we can compare to satisfy the functor's requirements (namely, is a strictly less-than b):

return (ad < bd);

The thing to keep in mind is that even though a and b are strings, you are not sorting by string comparison, but by an unusual criterion. That's why the need for the unusual sort function/functor.

Whew. Hope this helps.

I say the same, Whew :) That was a wonderful explanation.

So then I understand as you also wrote:
"Extraction stops with // the first invalid character in the istreams."

I have wondered for a while how the comparator really worked practically but this gives me a good understanding.
So for my strings, the double will be recogniced unil the first invalid character and it seems to work great.
Thank you for this help !

/J

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.