+ /*!
+ * This method tries to find the permutation to apply to the first input \a ids1 to obtain the same array (without considering strings information) the second
+ * input array \a ids2.
+ * \a ids1 and \a ids2 are expected to be both a list of ids (both with number of components equal to one) not sorted and with values that can be negative.
+ * This method will throw an exception is no such permutation array can be obtained. It is typically the case if there is some ids in \a ids1 not in \a ids2 or
+ * inversely.
+ * The difference with DataArrayInt::FindPermutationFromFirstToSecond is that this method supports multiple same values in \a ids1 and \a ids2 whereas
+ * DataArrayInt::FindPermutationFromFirstToSecond doesn't. It implies that this method my be slower than the DataArrayInt::FindPermutationFromFirstToSecond one.
+ *
+ * In case of success both assertion will be true (no throw) :
+ * \c ids1->renumber(ret)->isEqual(ids2) where \a ret is the return of this method.
+ * \c ret->transformWithIndArr(ids2)->isEqual(ids1)
+ *
+ * \b Example:
+ * - \a ids1 : [5, 3, 2, 1, 4, 5, 2, 1, 0, 11, 5, 4]
+ * - \a ids2 : [0, 1, 1, 2, 2, 3, 4, 4, 5, 5, 5, 11]
+ * - \a return is : [8, 5, 3, 1, 6, 9, 4, 2, 0, 11, 10, 7] because ids2[8]==ids1[0], ids2[5]==ids1[1], ids2[3]==ids1[2], ids2[1]==ids1[3]...
+ *
+ * \return DataArrayInt * - a new instance of DataArrayInt. The caller is to delete this
+ * array using decrRef() as it is no more needed.
+ * \throw If either ids1 or ids2 is null not allocated or not with one components.
+ *
+ * \sa DataArrayInt::findIdForEach, DataArrayInt::FindPermutationFromFirstToSecond, DataArrayInt::occurenceRankInThis
+ */
+ template<class T>
+ DataArrayIdType *DataArrayDiscrete<T>::FindPermutationFromFirstToSecondDuplicate(const DataArrayType *ids1, const DataArrayType *ids2)
+ {
+ if(!ids1 || !ids2)
+ throw INTERP_KERNEL::Exception("DataArrayInt::FindPermutationFromFirstToSecondDuplicate : the two input arrays must be not null !");
+ constexpr char MSG0[] = "DataArrayInt::FindPermutationFromFirstToSecondDuplicate :";
+ ids1->checkAllocated(); ids2->checkAllocated();
+ ids1->checkNbOfComps(1,MSG0); ids2->checkNbOfComps(1,MSG0);
+ mcIdType nbTuples(ids1->getNumberOfTuples());
+ if(nbTuples != ids2->getNumberOfTuples())
+ {
+ std::ostringstream oss; oss << "DataArrayInt::FindPermutationFromFirstToSecondDuplicate : first array has " << ids1->getNumberOfTuples() << " tuples and the second one " << ids2->getNumberOfTuples() << " tuples ! No chance to find a permutation between the 2 arrays !";
+ throw INTERP_KERNEL::Exception(oss.str().c_str());
+ }
+ MCAuto<DataArrayIdType> ret(DataArrayIdType::New()); ret->alloc(nbTuples,1);
+ MCAuto<DataArrayIdType> oids2(ids2->occurenceRankInThis());
+ std::map< std::pair<T,mcIdType>, mcIdType> m;
+ mcIdType pos(0);
+ const mcIdType *oids2Ptr(oids2->begin());
+ for(const T * it2 = ids2->begin() ; it2 != ids2->end() ; ++it2, ++oids2Ptr, ++pos)
+ m[{*it2,*oids2Ptr}] = pos;
+ mcIdType *retPtr(ret->getPointer());
+ //
+ std::map<T,mcIdType> mOccurence1; // see DataArrayInt::occurenceRankInThis : avoid to compute additionnal temporary array
+ //
+ for(const T * it1 = ids1->begin() ; it1 != ids1->end() ; ++it1, ++retPtr)
+ {
+ auto it = mOccurence1.find(*it1);
+ mcIdType occRk1;
+ if( it == mOccurence1.end() )
+ {
+ occRk1 = 0;
+ mOccurence1[*it1] = 1;
+ }
+ else
+ {
+ occRk1 = (*it).second++;
+ }
+ //
+ auto it2 = m.find({*it1,occRk1});
+ if(it2 != m.end())
+ {
+ *retPtr = (*it2).second;
+ }
+ else
+ {
+ std::ostringstream oss; oss << MSG0 << "At pos " << std::distance(ids1->begin(),it1) << " value is " << *it1 << " and occurence rank is " << occRk1 << ". No such item into second array !";
+ throw INTERP_KERNEL::Exception(oss.str());
+ }
+
+ }
+ return ret.retn();
+ }
+