Different Array Number

 

Hi,

I have a problem to count the number of different integer in an array.

For exemple: in MyArray {5,7,5,3,3,4,7,7,3,4,4,3}  There is 4 different integer (3, 4, 5 and 7)

I would like to return  int DifArrayNbr=4;

I've tried to did it with some "for() " or "while()" but it's so hard to make a correctly loop

Can someone help me please?

Mike

 
//{ Typedefs
#define  INDEX    uint           // Zero based.
#define  COUNT    uint           //  One based.
   #define INV_INDEX               UINT_MAX
   #define INV_COUNT               UINT_MAX
//} Typedefs
template <typename T>
COUNT    count_unique(T& array[], INDEX iEnd=INV_INDEX, INDEX iBeg=0){
   if(iEnd == INV_INDEX)   iEnd  = ArraySize(array);
   if(iEnd == iBeg)  return 0;            // Empty array.
   ArraySort(array, iEnd - iBeg, iBeg);
   COUNT    n  = 1;                       // Last is unique;
   while(--iEnd > iBeg) if(array[iEnd] != array[iEnd-1] )   ++n;
   return n;
}
/////////////////////////////////////////////////////
int      MyArray[] ={5,7,5,3,3,4,7,7,3,4,4,3};
COUNT    DifArrayNbr=count_unique(MyArray); // 4
 
whroeder1:
What is "COUNT" and "INDEX" types?
 
Put on your glasses and look at the code again.
 
aslkdjf:
What is "COUNT" and "INDEX" types?

The both are uint. This is whroeder's style but the code is worth it. Maybe it can be improved for double and float by using DBL_EPSILON.

 
Petr Nosek: Maybe it can be improved for double and float by using DBL_EPSILON.
//{ Typedefs
#define  PRICE double            // A PRICE
#define     PRICE_MAX   (PRICE)EMPTY_VALUE
#define     PRICE_MIN   (PRICE)0
#define     CHANGE      PRICE    // Difference of two prices.
#define  INDEX    uint           // Zero based.
#define  COUNT    uint           //  One based.
#define  MONEY    double
#define  LOTS     double
#define  SYMBOL   string
//} Typedefs
Don't need DBL_EPSILON as Tick Size or Point is sufficient.
 
Mickael Arditi:

Hi,

I have a problem to count the number of different integer in an array.

For exemple: in MyArray {5,7,5,3,3,4,7,7,3,4,4,3}  There is 4 different integer (3, 4, 5 and 7)

I would like to return  int DifArrayNbr=4;

I've tried to did it with some "for() " or "while()" but it's so hard to make a correctly loop

Can someone help me please?

Mike

I would have do it so, it's not as nerdy as the above snippet, but it works well : 

#include <Arrays\ArrayInt.mqh> // Include lib
//
int MyArray[]={5,7,5,3,3,4,7,7,3,4,4,3};
//
int CountItem(int &Array[])
  {
   CArrayInt *TempArray=new CArrayInt(); CArrayInt *ItemsFound=new CArrayInt(); int value = 0;
   TempArray.AssignArray(MyArray); TempArray.Sort();
   for(int x=0;x<TempArray.Total();x++) { if(ItemsFound.Search(TempArray.At(x))<0) { ItemsFound.Add(TempArray.At(x)); ItemsFound.Sort(); } else { continue; } }
   printf("*** Items found in array : %g",ItemsFound.Total()); value = ItemsFound.Total();
   delete(TempArray); delete(ItemsFound);
   return(value);
  }
//
DifArrayNbr = CountItem(MyArray); // Function call
//+------------------------------------------------------------------+
 
whroeder1:
Don't need DBL_EPSILON as Tick Size or Point is sufficient.

I've a little bit edited your function and it gives better results in my opinion. The last element in the double array is 3 like the previous one. For price is Tick Size or Point sufficient but for indicator values...

UPDATE: see the next post

template <typename T>
uint CountUnique(T& array[],const char precision=-1,uint iEnd=UINT_MAX,const uint iBeg=0)
  {
   if(iEnd==UINT_MAX) iEnd=ArraySize(array);
   if(iEnd==iBeg) return(0); // Empty array.
   ArraySort(array,iEnd-iBeg,iBeg);
   uint count=1; // Last is unique;
   string tn=typename(T);
   if((tn=="double"||tn=="float"))
     {
      if(precision>-1)
        {
         while(--iEnd>iBeg)
            if(DoubleToString(array[iEnd],precision)!=DoubleToString(array[iEnd-1],precision)) count++;
        }
      else
         while(--iEnd>iBeg)
            if(fabs(array[iEnd]-array[iEnd-1])>DBL_EPSILON*10) count++; // Too small difference => equal
     }
   else
      while(--iEnd>iBeg) if(array[iEnd]!=array[iEnd-1]) count++;
   return(count);
  }


   //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
   
   double dblArr[6]={1.0000001,1.0,1.4,1.399999,3.0,90000.0*123456789123456789.0/(30000.0*123456789123456789.0)};
   int intArr[12]={5,7,5,3,3,4,7,7,3,4,4,3};
   uint DifDblArrayNbr,DifIntArrayNbr;
   
   DifDblArrayNbr=CountUnique(dblArr);    // 5 (in your case 6)
   DifDblArrayNbr=CountUnique(dblArr,6);  // 4 
   DifDblArrayNbr=CountUnique(dblArr,5);  // 3
   DifDblArrayNbr=CountUnique(dblArr,0);  // 2
   
   DifIntArrayNbr=CountUnique(intArr);    // 4
 

Update: less code, same results


template <typename T>
uint CountUnique(T& array[],const char precision=-1,uint iEnd=UINT_MAX,const uint iBeg=0)
  {
   if(iEnd==UINT_MAX) iEnd=ArraySize(array);
   if(iEnd==iBeg) return(0); // Empty array.
   ArraySort(array,iEnd-iBeg,iBeg);
   uint count=1; // Last is unique;
   string tn=typename(T);
   if((tn=="double"||tn=="float"))
     {
      double difference=(precision>-1 && precision<16)?(pow(10.0,-1.0*precision)-pow(10.0,-1.0*(precision+1))):DBL_EPSILON*10;
      while(--iEnd>iBeg)
         if(fabs(array[iEnd]-array[iEnd-1])>difference) count++; // Too small difference => equal
     }
   else
      while(--iEnd>iBeg) if(array[iEnd]!=array[iEnd-1]) count++;
   return(count);
  }
 
Thank you very much for all your help! :) Have a very nice day ;)
Reason: