# How to count frequency of each element of array

Hello.
My puzzle today is to find out the frequency of each element in array.
By looking the code that found in C, I am not sure how to put it in exploration mode.
Also I think we have to use sort() and AddRow ()

Here is the link that found in C

Any comment welcome.
Thank you

You must run this afl in exploration, and ONLY one ticker/ symbol

``````/** count frequency of each element of array

Note: This is experimental code and NOT complete

1)	I am try to find out frequency of each element
2)	If one bar has number 125, then the following bar what number has? And how many percentages has happened this fact in the past.

*/

SegmentCount = 5;
SegmentDivisor = 100 / SegmentCount;
CandleRange = High - Low;
AvgRange = MA( CandleRange, 6 );
RangeMultiplier = CandleRange / AvgRange;  // Η-L / ma(H-L,6)
CandleRange /= 100;

RangeMultiplier = Min( RangeMultiplier, 1 );

HO = round( ( RangeMultiplier * ( High - Open ) / CandleRange ) / SegmentDivisor );
HC = round( ( RangeMultiplier * ( High - Close ) / CandleRange ) / SegmentDivisor );
OL = round( ( RangeMultiplier * ( Open - Low ) / CandleRange ) / SegmentDivisor );

DigitMult = SegmentCount + 1;
// signature is encoded to fit into integer
CandleSignature = DigitMult * DigitMult * HO + DigitMult * HC + OL;
printf( "\n  CandleSignature =\t" + CandleSignature );

////////////////////////////////////////////////////////////

if( Status( "Action" ) == actionExplore )
{
Filter = not( L == h ); // Clean the data of rubbish
SetOption( "NoDefaultColumns", True );
Range =  Cum( Status( "barinrange" ) );		// Count the bars that are in Range
RangeTotal = LastValue( range );  			// Total Of bars that are in Range
AddColumn( range, "# Bars", 1.0 );

// loop experimental to find the sum of the same Numbers
n = 50; // <= this has to set about 210
count = 0;      arr = 0;

for( i = 0; i < n ; i++ )
{
//Looks for the duplicates
for( j = i + 1; j < n ; j++ )
{
//_TRACE( "#, I= " + i + ",j= " + j + ",cdSig[i]= " + CandleSignature[i] ) ;

// If duplicate found then increment count by 1
//if(arr[i]==arr[j])
if( CandleSignature[i] == CandleSignature[j] )
{
count++;
_TRACE( "#, I= " + i + ",j= " + j + ",count= " + count + ",cdSig[i]= " + CandleSignature[i]) ;
//Makes sure not to count next duplicate of current element
break;
}
}
}

}
``````

Sorry i think i had a long day today the code that I post above is based to the link count total duplicate elements in an array

was from last night… Sorry i have to write other code based to my question

1 Like

What I am looking is to find the frequency of the numbers that appears in the column Signature Sort the array first and then you would easily count the number of unique values http://www.amibroker.com/f?sort

``````x = Sort( array );
count = SumSince( x != ref( x, -1 ), 1 );
``````
3 Likes

@Tomasz thank you for your time
I have an issue here with the Sort

Why the example that you have in the manual sorting the array perfect, But not the array in the current code? What I am missing here.

AddColumn( Sort( Close ), "Sorted Close" ); // form the manual

// This line does NOT Sort sort the array. what i am doing wrong in here?
array = CandleSignature;
AddColumn( Sort( array ), "Sorted array" );

Can you please check the below code

``````// run in exploration Mode, and just One Ticker
SegmentCount = 5;
SegmentDivisor = 100 / SegmentCount;
CandleRange = High - Low;
AvgRange = MA( CandleRange, 6 );
RangeMultiplier = CandleRange / AvgRange;  // Η-L / ma(H-L,6)
CandleRange /= 100;
RangeMultiplier = Min( RangeMultiplier, 1 );
HO = round( ( RangeMultiplier * ( High - Open ) / CandleRange ) / SegmentDivisor );
HC = round( ( RangeMultiplier * ( High - Close ) / CandleRange ) / SegmentDivisor );
OL = round( ( RangeMultiplier * ( Open - Low ) / CandleRange ) / SegmentDivisor );
DigitMult = SegmentCount + 1;
// signature is encoded to fit into integer
CandleSignature = DigitMult * DigitMult * HO + DigitMult * HC + OL;
printf( "\n  CandleSignature =\t" + CandleSignature );

array = CandleSignature;

if( Status( "Action" ) == actionExplore )
{
Filter = 1;
SetOption( "NoDefaultColumns", True );

// help by Tomasz this line with SumSince works fine
count = SumSince( array != ref( array, -1 ), 1 );
AddColumn( count , " Count" ,1);

// -------------------------------
//  What i am doing wrong in here?
// This line with the Sort() does NOT sort the array.
AddColumn( Sort( array ), "Sorted array" );

}
`````` Trying to save Tomasz some time...

Two mistakes/missings:

1. Your code divides by zero i.e.

``````HO = round( ( RangeMultiplier * ( High - Open ) / CandleRange ) / SegmentDivisor );
``````

which will result in NAN (not a number) at some elements of array because of array variable CandleRange may be getting zero at some elements.

So to avoid that

``````range_not_zero = CandleRange+1e-9;
HO = round( ( RangeMultiplier * ( High - Open ) / range_not_zero) / SegmentDivisor );
``````

same for the other two variables...

1. As for Sort() function.. in your picture you want to output From-To analysis range so it is a segment of entire array. So you would have to define start and end bar of sorting since otherwise Sort() function would sort based on entire Barcount (see 2nd picture below).
``````x = Sort( array, startbar, endbar);
``````

So, "fixed" code

``````// run in exploration Mode, and just One Ticker
SegmentCount = 5;
SegmentDivisor = 100 / SegmentCount;
CandleRange = High - Low;
AvgRange = MA( CandleRange, 6 );
RangeMultiplier = CandleRange / AvgRange;  // ?-L / ma(H-L,6)
CandleRange /= 100;
RangeMultiplier = Min( RangeMultiplier, 1 );
range_not_zero = CandleRange+1e-9;
HO = round( ( RangeMultiplier * ( High - Open ) / range_not_zero ) / SegmentDivisor );
HC = round( ( RangeMultiplier * ( High - Close ) / range_not_zero) / SegmentDivisor );
OL = round( ( RangeMultiplier * ( Open - Low ) / range_not_zero ) / SegmentDivisor );
DigitMult = SegmentCount + 1;
// signature is encoded to fit into integer
CandleSignature = DigitMult * DigitMult * HO + DigitMult * HC + OL;
printf( "\n  CandleSignature =\t" + CandleSignature );

array = CandleSignature;
if( Status( "Action" ) == actionExplore )
{
Filter = 1;
SetOption( "NoDefaultColumns", True );
AddColumn( array , "Signature", 1.0 );

// help by Tomasz this line with SumSince works fine
count = SumSince( array != ref( array, -1 ), 1 );
AddColumn( count , " Count" , 1 );

// -------------------------------
// in order to sort selected analysis range start and end bar need to be defined within Sort().
bi = Barindex();
fbr = LastValue( Valuewhen( Status( "firstbarinrange" ), bi ) );
lbr = LastValue( Valuewhen( Status( "lastbarinrange" ), bi ) );
x = Sort( array, fbr, lbr );
}
``````

And as you can see values of selected range are being sorted From AFL Function Reference Guide. BTW, I am not 100% sure but there seems to be a small typo in T.J.'s upper code
I think it should be

``````x = Sort( array );
count = SumSince( x != ref( x, -1 ), 1 );
``````

Since you seem to want to get frequency of sorted array

``````// run in exploration Mode, and just One Ticker
SegmentCount = 5;
SegmentDivisor = 100 / SegmentCount;
CandleRange = High - Low;
AvgRange = MA( CandleRange, 6 );
RangeMultiplier = CandleRange / AvgRange;  // ?-L / ma(H-L,6)
CandleRange /= 100;
RangeMultiplier = Min( RangeMultiplier, 1 );
range_not_zero = CandleRange+1e-9;
HO = round( ( RangeMultiplier * ( High - Open ) / range_not_zero ) / SegmentDivisor );
HC = round( ( RangeMultiplier * ( High - Close ) / range_not_zero) / SegmentDivisor );
OL = round( ( RangeMultiplier * ( Open - Low ) / range_not_zero ) / SegmentDivisor );
DigitMult = SegmentCount + 1;
// signature is encoded to fit into integer
CandleSignature = DigitMult * DigitMult * HO + DigitMult * HC + OL;
printf( "\n  CandleSignature =\t" + CandleSignature );

array = CandleSignature;

if( Status( "Action" ) == actionExplore )
{
Filter = 1;
SetOption( "NoDefaultColumns", True );
AddColumn( array , "Signature", 1.0 );

// help by Tomasz this line with SumSince works fine
count = SumSince( array != Ref( array, -1 ), 1 );
AddColumn( count , " Count" , 1 );

// -------------------------------
//  What i am doing wrong in here?
// This line with the Sort() does NOT sort the array.
bi = Barindex();
fbr = LastValue( Valuewhen( Status( "firstbarinrange" ), bi ) );
lbr = LastValue( Valuewhen( Status( "lastbarinrange" ), bi ) );
x = Sort( array, fbr, lbr );

count = SumSince( x != Ref( x, -1 ), 1 ) + 1;
}

`````` 17 Likes

Yes I was just typing it very quickly in the browser and @fxshrat spotted out that correctly it should be `x` inside braces. I always try to give fishing pole (explain the idea) than to give fish. Giving ready-to-use code while expected/welcomed by “copy-pasters” is not good for people wanting to learn. Learning by doing/trying is best.

Briliant… @fxshrat we like it when you save someone time …. Especially Tomasz
Thank you

This problem was very brilliantly solved by @fxshrat and it showed us how to properly use the Sort() function of AmiBroker.

So, as an exercise, today I decided to spend some time reviewing and porting some standard sorting algos to AFL.

Keep in mind that actually there was no need for it since the native Sort() (and also MxSort() , MxSortRows()) are quite fast because they implement the QuickSort algorithm.

Anyway, I did it to see how easy/difficult was to port some standard source code to AFL from other similar programming languages.

In the sample code below, you’ll see the reference to the site that I used to actually “copy & adapt” (mainly from C# examples) the different sorting algos.
I slightly modified them adding the possibility to sort a range instead of a full array.

While I did not test them quite extensively they seem to work as expected.

Obviously, the native Sort() is the fastest one (by a lot!) and the BubbleSort is the worst. The ShellSort is not that bad for small tasks.

If you test them with a symbol with a lot of quotes, keep in mind that it could take some seconds (minutes) to complete since some of these algos are quite slow.

As said, not very useful, but here it is:

``````//*****************************************************************
// Sorting Algorithms vs AmiBroker native Sort (QuickSort)
//
// Porting to AFL some common sorting algorithms
// Original C# code found at:
// https://rosettacode.org/wiki/Category:Sorting_Algorithms
// Added the feature to sort a range instead of the full array
//
// All the sorting algos are implemented as procedures that sort
// a "passed by reference" array in place (no return value)
// Each sorting procedure requires 3 parameters:
// SortXxxxxxxx(list, b, e)
// list: is an array and MUST be passed by reference (sort in place)
// b: is the index of the start of range to sort (b for beginning)
// e: is the index of the end of range to sort (e for ending)
//
// To be used in Analysis - Explore
// Apply to: "Current" - Range From/To Dates or All quotes
//
// Performances reported via _TRACEF to the internal/external log
//*****************************************************************

Version (6.26);  // Uses passing by reference arrays

//// https://rosettacode.org/wiki/Sorting_algorithms/Bubble_sort
procedure BubbleSort(list, b, e) // Pass the array param by REFERENCE
{
// Because of its abysmal O(n2) performance, it is not used often for large
// (or even medium-sized) datasets.
itemCount = (e-b) + 1;
do
{
swapped = false;
itemCount--;
for (i = 0; i < itemCount; i++)
{
j = i+b; // offset from begin of interval
if (list[j] > list[j + 1]) {
temp = list[j + 1];
list[j + 1] = list[j];
list[j] = temp;
swapped = true;
}
}
} while (swapped);
}

/// https://rosettacode.org/wiki/Sorting_algorithms/Cocktail_sort
procedure CocktailSort(list, b, e) // Pass the array param by REFERENCE - a.k.a SharerSort
{
// The cocktail shaker sort is a small improvement on the Bubble Sort.
// Sometime, performance is slightly better.
itemCount = (e-b) + 1;
do
{
swapped = false;
for (i = 0; i <= itemCount - 2; i++)
{
j = i+b;
if (list[j] > list[j + 1])
{
// test whether the two elements are in the wrong order
temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
if (!swapped)
{
// We can exit the outer loop here if no swaps occurred.
break;
}
swapped = false;
for (i = itemCount - 2; i >= 0; i--)
{
j = i+b;
if (list[j] > list[j + 1])
{
temp = list[j];
list[j] = list[j + 1];
list[j + 1] = temp;
swapped = true;
}
}
// If no elements have been swapped, then the list is sorted
} while (swapped);
}

//// https://rosettacode.org/wiki/Sorting_algorithms/Selection_sort
procedure SelectionSort( list, b, e ) // Pass the array param by REFERENCE
{
// Its asymptotic complexity is O(n2) making it inefficient on large arrays.
itemCount = ( e - b ) + 1;
for( i = 0; i < itemCount; i++ ) {
k = i;
for( j = i + 1; j < itemCount; j++ )  {
if( list[j+b] < list[k+b] ) {
k = j;
}
}
temp = list[i+b];
list[i+b] = list[k+b];
list[k+b] = temp;
}
}

// https://rosettacode.org/wiki/Sorting_algorithms/Insertion_sort
procedure InsertionSort( list, b, e ) // Pass the array param by REFERENCE
{
// An O(n2) sorting algorithm which moves elements one at a time into
// the correct position
for( i = 1+b; i <= e; i++ ) {
temp = list[i];
j = i;
while (( j > b ) AND( list[j - 1] > temp )) {
list[j] = list[j - 1];
j--;
}
list[j] = temp;
}
}

//// https://rosettacode.org/wiki/Sorting_algorithms/Comb_sort
procedure CombSort( list, b, e ) // Pass the array param by REFERENCE
{
// The Comb Sort is a variant of the Bubble Sort. Like the Shell sort,
// it increases the gap used in comparisons and exchanges.
// Frequently has a fairly rapid execution.
itemCount = ( e - b ) + 1;
gap = itemCount;
swaps = true;
while( ( gap > 1 ) OR swapped ) {
gap /= 1.247330950103979;
if( gap < 1 )
gap = 1;
i = 0;
swapped = false;
while( ( i + gap ) < itemCount ) {
igap = i + int(gap);
if( list[i+b] > list[igap+b] ) {
temp = list[i+b];
list[i+b] = list[igap+b];
list[igap+b] = temp;
swapped = true;
}
i++;
}
}
}

//// https://rosettacode.org/wiki/Sorting_algorithms/Shell_sort
procedure ShellSort( list, b, e ) // Pass the param by REFERENCE
{
// Shellsort is a generalization of insertion sort that allows the
// exchange of items that are far apart.
// The running time of Shellsort is heavily dependent on the gap sequence it uses
// Using Shell's original gap sequence makes T(N2) comparisons in the worst case.
n = (e-b) + 1;
gap = 1;
while( gap < int( n / 2 ) )  {
gap = ( gap * 2 ) + 1;
}
while( gap >= 1 ) {
for( i = gap; i < n; i++ ) {
k = i - gap;
j = i;
for( j = i; (j >= gap) AND (list[j+b] < list[k+b] ); k -= gap ) {
temp = list[j+b];
list[j+b] = list[k+b];
list[k+b] = temp;
j = k;
}
}
gap = int( gap / 2 );
}
}

//// https://rosettacode.org/wiki/Sorting_algorithms/Shell_sort
//// https://oeis.org/search?q=shell+sort
procedure ShellSortCiura( list, b, e ) // Pass the param by REFERENCE
{
// ShellSort variation using predefined gaps sequence
n = (e-b) + 1;
// Using Marcin Ciura's gap sequence (2001) - https://oeis.org/A102549
gaps = MxFromString("{{1750, 701, 301, 132, 57, 23, 10, 4, 1 }}");
for (g = 0; g < MxGetSize(gaps, 1); g++) {
gap = gaps[g];
for( i = gap; i < n; i++ ) {
k = i - gap;
j = i;
for( j = i; (j >= gap) AND (list[j+b] < list[k+b] ); k -= gap ) {
temp = list[j+b];
list[j+b] = list[k+b];
list[k+b] = temp;
j = k;
}
}
}
}

// Sample code to test the sorting algos performance.
// Run in exploration mode: Apply to: "Current" - Range From/To Dates or All quotes

array = V / 1000; // Any array of values

if( Status( "Action" ) == actionExplore )
{
Filter = 1;
SetOption( "NoDefaultColumns", True );

bi = Barindex();
fbr = LastValue( Valuewhen( Status( "firstbarinrange" ), bi ) );
lbr = LastValue( Valuewhen( Status( "lastbarinrange" ), bi ) );

bsa = array; // BubbleSort
cka = array; // CocktailSort
sea = array; // SelectionSort
isa = array; // InsertionSort
csa = array; // CombSort
ssa = array; // ShellSort
sca = array; // ShellSort (Ciura)
qsa = array; // QuickSort (AmiBroker internal - FASTEST)

GetPerformanceCounter(True); // reset counter to zero
BubbleSort( &bsa, fbr, lbr );
bsa_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True); // reset counter to zero
CocktailSort( &cka, fbr, lbr );
cka_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
SelectionSort( &sea, fbr, lbr );
sea_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
InsertionSort( &isa, fbr, lbr );
isa_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
CombSort( &csa, fbr, lbr );
csa_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
ShellSort( &ssa, fbr, lbr );
ssa_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
ShellSortCiura( &sca, fbr, lbr );
sca_elapsed =GetPerformanceCounter();

GetPerformanceCounter(True);
qsa = Sort(qsa, fbr, lbr ); // AmiBroker sort is a function returning the sorted array
qsa_elapsed =GetPerformanceCounter();

AddColumn( sca, "Sh. Sort Ciura" );

_TRACEF("----------------------------------------------------------------");
_TRACEF("Sorting arrays - Ticker: " + Name());
_TRACEF("BarCount %6.0f - FvB %6.0f - LvB %6.0f - Bars in range %6.0f",
BarCount, fbr, lbr, (lbr-fbr)+1);
_TRACEF("----------------------------------------------------------------");
_TRACEF("BubbleSort      : %7.3f ms", bsa_elapsed);
_TRACEF("CocktailSort    : %7.3f ms", cka_elapsed);
_TRACEF("SelectionSort   : %7.3f ms", sea_elapsed);
_TRACEF("InsertionSort   : %7.3f ms", isa_elapsed);
_TRACEF("CombSort        : %7.3f ms", csa_elapsed);
_TRACEF("ShellSort       : %7.3f ms", ssa_elapsed);
_TRACEF("Sh.Sort (Ciura) : %7.3f ms", sca_elapsed);
_TRACEF("QuickSort (AB)  : %7.3f ms", qsa_elapsed); // A LOT FASTER!!!
_TRACEF("----------------------------- DONE -----------------------------");

}
``````
13 Likes