masterofpuppets/Include/MasterOfPuppetsLib/DuplicateFinder.mqh

130 lines
4.6 KiB
MQL5
Raw Permalink Normal View History

2026-03-03 01:24:43 +03:00
//+------------------------------------------------------------------+
//| DuplicateFinder.mqh |
//| Copyright 2026, MasterOfPuppets |
//| https://forge.mql5.io/masterofpuppets/mql5 |
//+------------------------------------------------------------------+
2026-03-03 01:41:15 +03:00
#ifndef MASTER_OF_PUPPETS_LIB_DUPLICATE_FINDER_MQH
#define MASTER_OF_PUPPETS_LIB_DUPLICATE_FINDER_MQH
2026-03-03 01:24:43 +03:00
2026-03-20 23:07:59 +03:00
#include <Arrays\ArrayObj.mqh>
#include <Generic\ArrayList.mqh>
#include <Generic\SortedMap.mqh>
2026-03-03 01:24:43 +03:00
#property copyright "Copyright 2026, MasterOfPuppets"
#property link "https://forge.mql5.io/masterofpuppets/mql5"
2026-03-20 23:07:59 +03:00
//+------------------------------------------------------------------+
//| Classes |
//+------------------------------------------------------------------+
class ArrayListWrapper : public CObject
{
public:
CArrayList<uint> *arrayList;
ArrayListWrapper() { arrayList = new CArrayList<uint>(); }
~ArrayListWrapper() { delete arrayList; }
};
2026-03-03 01:24:43 +03:00
//+------------------------------------------------------------------+
//| Structs |
//+------------------------------------------------------------------+
template<typename T>
struct DuplicateResult
{
T value;
uint indices[];
};
//+------------------------------------------------------------------+
//| Duplicate finder class |
//+------------------------------------------------------------------+
template<typename T>
class DuplicateFinder
{
public:
2026-03-20 23:07:59 +03:00
static void FindUsingArrays(const T &source[], DuplicateResult<T> &duplicateResults[])
2026-03-03 01:24:43 +03:00
{
int sourceSize = ArraySize(source);
if(sourceSize <= 1)
{
return;
}
2026-03-20 23:07:59 +03:00
ArrayFree(duplicateResults);
2026-03-03 01:24:43 +03:00
bool processed[];
ArrayResize(processed, sourceSize);
ArrayInitialize(processed, false);
for(int i = 0; i < sourceSize; i++)
{
if(processed[i])
{
continue;
}
int foundCount = 0;
int tempIndices[];
for(int j = i; j < sourceSize; j++)
{
if(source[i] == source[j])
{
ArrayResize(tempIndices, foundCount + 1);
tempIndices[foundCount] = j;
foundCount++;
if(j != i)
{
processed[j] = true;
}
}
}
if(foundCount > 1)
{
2026-03-20 23:07:59 +03:00
int duplicateResultsSize = ArraySize(duplicateResults);
ArrayResize(duplicateResults, duplicateResultsSize + 1);
duplicateResults[duplicateResultsSize].value = source[i];
ArrayCopy(duplicateResults[duplicateResultsSize].indices, tempIndices);
}
}
}
static void Find(const T &source[], DuplicateResult<T> &duplicateResults[])
{
int sourceSize = ArraySize(source);
if(sourceSize <= 1)
{
return;
}
CArrayObj garbageCollector;
garbageCollector.FreeMode(true);
CSortedMap<T, ArrayListWrapper*> duplicatesMap;
for(int i = 0; i < sourceSize; i++)
{
T value = source[i];
ArrayListWrapper *arrayListWrapper = NULL;
if(!duplicatesMap.TryGetValue(value, arrayListWrapper))
{
arrayListWrapper = new ArrayListWrapper();
duplicatesMap.Add(value, arrayListWrapper);
garbageCollector.Add(arrayListWrapper);
}
arrayListWrapper.arrayList.Add(i);
}
ArrayFree(duplicateResults);
T duplicatesMapKeys[];
ArrayListWrapper* duplicatesMapValues[];
duplicatesMap.CopyTo(duplicatesMapKeys, duplicatesMapValues);
for(int i = 0; i < ArraySize(duplicatesMapKeys); i++)
{
T duplicatesMapKey = duplicatesMapKeys[i];
ArrayListWrapper *arrayListWrapper = duplicatesMapValues[i];
if(arrayListWrapper.arrayList.Count() > 1)
{
int duplicateResultsSize = ArraySize(duplicateResults);
ArrayResize(duplicateResults, duplicateResultsSize + 1);
duplicateResults[duplicateResultsSize].value = duplicatesMapKey;
uint indices[];
arrayListWrapper.arrayList.CopyTo(indices);
ArrayCopy(duplicateResults[duplicateResultsSize].indices, indices);
2026-03-03 01:24:43 +03:00
}
}
}
};
#endif
//+------------------------------------------------------------------+