Sorting 2 array with different types

 
string fxsymbols[3];
double pipschange[3];

fxsymbols[0]="AUDUSD";
fxsymbols[1]="EURUSD";
fxsymbols[2]="USDJPY";
pipschange[0]=10;
pipschange[1]=-8;
pipschange[
2]=3;

Hey everyone,

I have to arrays that are related to another. That means AUDUSD changed 10 pips, EURUSD changed -8 pips and USDJPY changed 3 pips. I wanna sort the array pipschange with the ArraySort() function. How can do make sure, that the related fxsymbols array also change in the right direction?

After sorting I wanna have the result:

AUDUSD 10
USDJPY 3
EURUSD -8

Thanks for help.

 
Dan: How can do make sure,
  1. You don't. Sorting one array has nothing to do with another.
  2. You'll have to do your own sorting. Start with an array of a structure.
    struct Change{ string symbol; double pips; };
    Change data[] = { "AUDUSD", 10,
                      "EURUSD", -8,
                      "USDJPY",  3 };
    then choose whether you want to use my way,
    class OrderByPips{ public:
      bool is_before(const Change& lhs, const Change& rhs){ return lhs.Pips < rhs.Pips; }
    };
    OrderByPip obp; insertion_sort(data, 0 , ArraySize(data), obp);
              Sort multiple arrays - MQL4 programming forum
              Array or not to array - Trading Positions - MQL4 programming forum - Page 2

    or CList route.
              pass generic class data field - Swing Trades - MQL4 programming forum

 
Dan:

Hey everyone,

I have to arrays that are related to another. That means AUDUSD changed 10 pips, EURUSD changed -8 pips and USDJPY changed 3 pips. I wanna sort the array pipschange with the ArraySort() function. How can do make sure, that the related fxsymbols array also change in the right direction?

After sorting I wanna have the result:

AUDUSD 10
USDJPY 3
EURUSD -8

Thanks for help.

Use this way for sorting : https://www.mql5.com/en/forum/312388#comment_11532277

How to sort struct variables in MT4?
How to sort struct variables in MT4?
  • 2019.05.01
  • www.mql5.com
Hi I'm using a struct for collecting the data which includes spreads and their instances...
 
William Roeder:
  1. You don't. Sorting one array has nothing to do with another.
  2. You'll have to do your own sorting. Start with an array of a structure. then choose whether you want to use my way,           Sort multiple arrays - MQL4 programming forum
              Array or not to array - Trading Positions - MQL4 programming forum - Page 2

    or CList route.
              pass generic class data field - Swing Trades - MQL4 programming forum

Thanks Willam Roeder, I wanna go your suggested way. I try my best to figure out what I've learned in OOP years ago ...


I guess ChangeByPip obp must be OrderByPips obp what means obp is an object of the class OrderByPips, am I right?

How can I initialize the obp object before calling the insertion_sort function? Otherwise I'll get an error 'obp' - objects are passed by reference only.

And if I use in the function call  &obp, I'll get the error 'unguarded_linear_insert' - no one of the overloads can be applied to the function call.

Thanks for help!


 

Here's an example of how to do it with a 2-dimensional array. You just sort the indexes (2nd column) together with its values.

https://www.mql5.com/en/forum/303631#comment_10640678

how to sort and display in color
how to sort and display in color
  • 2019.02.14
  • www.mql5.com
Say I have follow data Nr. B/S Pair Profit 1 Buy EURUSD -90.12 2. Sell USDJPY 100.04 3. Sell AUDUSD -100.12 4. Buy GBPUSD -123.34 5...
 
lippmaje: Here's an example of how to do it with a 2-dimensional array.

Irrelevent. A 2D array have the same data type. OP has a string and a number.

 
William Roeder:

Irrelevent. A 2D array have the same data type. OP has a string and a number.

The idea of this solution is to sort a column of indexes together with the numbers, so that afterwards you may use the indexes to access the strings.

string fxsymbols[]= { "AUDUSD", "EURUSD", "USDJPY" };
double indexmap[][2];
int rows=ArraySize(fxsymbols);
ArrayResize(indexmap,rows);

for(int i=0; i<rows; i++) {
   double pipschange=GetPipsChange(fxsymbols[i]);
   indexmap[i][0]=pipschange;
   indexmap[i][1]=i;
}
//--- sorting of indexmap[][] by first dimension (descending) 
ArraySort(indexmap,WHOLE_ARRAY,0,MODE_DESCEND); 
//--- indexmap is now sorted by pips change, descending, together with index, like so: [8.34, 2], [1.04, 0], ...

for(int j=0; j<rows; j++) {
   double pipschange=indexmap[j][0];
   int i=(int)indexmap[j][1];
   Print(fxsymbols[i]," changed by ",DoubleToString(pipschange,2)," pips");
}
 
Dan:

Thanks Willam Roeder, I wanna go your suggested way. I try my best to figure out what I've learned in OOP years ago ...


I guess ChangeByPip obp must be  OrderByPips obp what means obp is an object of the class OrderByPips, am I right?

How can I initialize the obp object before calling the insertion_sort function? Otherwise I'll get an error 'obp' - objects are passed by reference only.

And if I use in the function call  &obp, I'll get the error 'unguarded_linear_insert' - no one of the overloads can be applied to the function call.

Thanks for help!


I would avoid using that method and instead use the commonly used MQL convention for object collections and sorting. You will need to subclass CObject and override its Compare method, and then add the dynamically allocated object pointers to a pointer collection, i.e. CList or CArrayObj. You can then call the Sort method on the collection itself. This is the only way I'd recommend implementing what you are trying to do since it is how all of the MQL-standard-library code handles object sorting.  


#include <arrays/list.mqh>
#define SORT_NUMBER 0
#define SORT_TEXT 1

class TextNumber : public CObject {
 public:
                  TextNumber(string t, int n):text(t), number(n){}
   string         text;
   int            number;
   virtual int    Compare(const CObject *node, const int mode=0) const override;
   virtual string toString() const;
};

int TextNumber::Compare(const CObject *node, const int mode=0) const override {
   const TextNumber *other = node;
   if (mode == SORT_NUMBER) {
      if (this.number > other.number)
         return 1;
      if (this.number < other.number)
         return -1;
   } 
   else if (mode == SORT_TEXT) {
      return StringCompare(this.text, other.text);
   }
   return 0;
}

string TextNumber::toString() const {
   return StringFormat(
      "Text = %s, Number = %d",
      this.text,
      this.number
   );
}


void OnStart() {
   CList myList();
   myList.Add(new TextNumber("ABC", 5));
   myList.Add(new TextNumber("BAC", 1));
   myList.Add(new TextNumber("CAB", 3));
   
   Print("Sorted by number...");
   myList.Sort(SORT_NUMBER);
   for (TextNumber *x=myList.GetFirstNode(); CheckPointer(x); x=x.Next())
      Print(x.toString());
   
   Print("Sorted by text...");
   myList.Sort(SORT_TEXT);
   for (TextNumber *x=myList.GetFirstNode(); CheckPointer(x); x=x.Next())
      Print(x.toString());
}
 
nicholi shen:

I would avoid using that method and instead use the commonly used MQL convention for object collections and sorting. You will need to subclass CObject and override its Compare method, and then add the dynamically allocated object pointers to a pointer collection, i.e. CList or CArrayObj. You can then call the Sort method on the collection itself. This is the only way I'd recommend implementing what you are trying to do since it is how all of the MQL-standard-library code handles object sorting.  


Thanks for your help. The suggested solution works fine when I only need to print  the results.

But for further operations I need to access the single values for the symbol (AUDUSD, EURUSD, USDJPY) and the related changed pips (2, -2.5, -7). So for that purpose the datatype struct would make more sense? Am I right?

So I try to adapt your solution to my case of a struct datatype.

Thanks again guys for all the input!

 
lippmaje:

Here's an example of how to do it with a 2-dimensional array. You just sort the indexes (2nd column) together with its values.

https://www.mql5.com/en/forum/303631#comment_10640678

Thanks for your solution. I tested it in my case and it worked. I use the value in the indexmap array as a reference to my other array where I stored the symbol names.

Here's how it works.

#property copyright "2019"
#property link      "https://www.mql5.com"
#property version   "1.00"
#property strict
#property indicator_chart_window

string fxgroupnames[3];
double fxgrouppricechange[3];
double indexmap[3][2];
//+------------------------------------------------------------------+
//| Custom indicator initialization function                         |
//+------------------------------------------------------------------+
int OnInit()
  {
   fxgroupnames[0]="AUD";
   fxgroupnames[1]="EURJPY";
   fxgroupnames[2]="USDJPY";

   fxgrouppricechange[0]=0.25;
   fxgrouppricechange[1]=-0.3;
   fxgrouppricechange[2]=0.55;

//---
   return(INIT_SUCCEEDED);
  }
//+------------------------------------------------------------------+
//|                                                                  |
//+------------------------------------------------------------------+
void OnDeinit(const int reason)
  {

  }
//+------------------------------------------------------------------+
//| Custom indicator iteration function                              |
//+------------------------------------------------------------------+
int OnCalculate(const int rates_total,
                const int prev_calculated,
                const datetime &time[],
                const double &open[],
                const double &high[],
                const double &low[],
                const double &close[],
                const long &tick_volume[],
                const long &volume[],
                const int &spread[])
  {

   Print("result before sorting");

   for(int i=0; i<3; i++)
     {
      Print(i," ",fxgroupnames[i]," ",DoubleToStr(fxgrouppricechange[i],2)," %");
     }

//--- filling the indexmap
   for(int i=0; i<3; i++)
     {
      indexmap[i][0]=fxgrouppricechange[i];
      indexmap[i][1]=i;
     }

//--- sorting of indexmap[][] by first dimension (descending) 
   ArraySort(indexmap,WHOLE_ARRAY,0,MODE_DESCEND);
//--- indexmap is now sorted by fxgrouppricechange, descending, together with index, like so: [0.55, 2], [0.25, 0], [-3.0, 1] 

   Print("result after sorting");

   for(int i=0; i<3; i++)
     {
      Print(i," ",fxgroupnames[(int)indexmap[i][1]]," ",DoubleToStr(indexmap[i][0],2)," %");
     }

   return(rates_total);
  }

So with that kind of solution my problem is solved! Thanks. W.H. Roeder: actually I like the way by using a struct datatyp more, but unfortunately it took me too long to discover. Anyway I will also try that way and post it here.

 
Dan:

Thanks for your help. The suggested solution works fine when I only need to print  the results.

But for further operations I need to access the single values for the symbol (AUDUSD, EURUSD, USDJPY) and the related changed pips (2, -2.5, -7). So for that purpose the datatype struct would make more sense? Am I right?

So I try to adapt your solution to my case of a struct datatype.

Thanks again guys for all the input!

You can't assign struct objects to pointers in MQL... it's one of the weird quirks of the language. Unless you're inheriting a builtin struct, always use classes instead. When you get better at OOP use in MQL you will be thankful you built your libraries using the same design patterns that metaquotes uses instead of rolling spaghetti code that's more like a rube-goldberg machine... Using multi-dimensional native arrays to store index elements to be used in another array is a huge red-flag that one doesn't have a command over the language, and should spend some time with some C++ tutorials to better understand how to build clean D.R.Y. code.     

Reason: