J'utilise un type de données de std::vector<std::vector<T> >
pour stocker une matrice/matrice 2D. Je voudrais déterminer les rangées uniques de cette matrice. Je suis à la recherche de conseils ou de conseils sur la façon de faire cette opération.Détermination des lignes uniques d'un tableau 2D (vecteur <vector<T>>)
J'ai essayé deux méthodes.
Méthode 1: légèrement convoluté. Je garde un index pour chaque ligne avec 0/1 indiquant si la ligne est une valeur dupliquée, et travaille à travers la matrice, en stockant l'index de chaque ligne unique dans un deque
. Je veux stocker les résultats dans un <vector<vector<T> >
, et donc à partir de cette liste d'indices, je pré-allouer, puis affecter les lignes de la matrice dans la valeur de retour. Méthode 2: Est plus facile à lire, et dans de nombreux cas plus rapide que la méthode 1. Je garde une trace des lignes uniques qui ont été trouvées, et je fais juste une boucle dans les lignes et compare chaque ligne à toutes les entrées de cette deque
.
Je compare ces deux méthodes à matlab, et ces routines C++ sont plus lentes. Est-ce que quelqu'un a des idées intelligentes sur la façon dont je pourrais accélérer cette opération? Je cherche à faire cette opération sur des matrices qui ont potentiellement des millions de lignes.
Je stocke les lignes uniques dans une deque pendant la boucle pour éviter le coût de redimensionner un vecteur, puis en copiant le deque
au vector<vector<T> >
pour les résultats. J'ai comparé cette opération de près, et elle ne ralentit pas l'opération, elle représente moins de 0,5% de l'exécution sur une matrice de 100 000 lignes par exemple.
Merci,
Bob
Voici le code. Si quelqu'un est intéressé par un exemple plus complet montrant l'utilisation, laissez-moi un commentaire et je peux mettre quelque chose ensemble.
Méthode 1:
template <typename T>
void uniqueRows(const std::vector<std::vector<T> > &A,
std::vector<std::vector<T> > &ret) {
// Go through a vector<vector<T> > and find the unique rows
// have a value ind for each row that is 1/0 indicating if a value
// has been previously searched.
// cur : current item being compared to every item
// num : number of values searched for. Once all the values in the
// matrix have been searched, terminate.
size_t N = A.size();
size_t num=1,cur=0,it=1;
std::vector<unsigned char> ind(N,0);
std::deque<size_t> ulist; // create a deque to store the unique inds
ind[cur] = 1;
ulist.push_back(0); // ret.push_back(A[0]);
while(num < N) {
if(it >= N) {
++cur; // find next non-duplicate value, push back
while(ind[cur])
++cur;
ulist.push_back(cur); //ret.push_back(A[cur]);
++num;
it = cur+1; // start search for duplicates at the next row
if(it >= N && num == N)
break;
}
if(!ind[it] && A[cur]==A[it]) {
ind[it] = 1; // mark as duplicate
++num;
}
++it;
} // ~while num
// loop over the deque and .push_back the unique vectors
std::deque<size_t>::iterator iter;
const std::deque<size_t>::iterator end = ulist.end();
ret.reserve(ulist.size());
for(iter= ulist.begin(); iter != end; ++iter) {
ret.push_back(A[*iter]);
}
}
Voici le code pour la méthode 2:
template <typename T>
inline bool isInList(const std::deque< std::vector<T> > &A,
const std::vector<T> &b) {
typename std::deque<std::vector<T> >::const_iterator it;
const typename std::deque<std::vector<T> >::const_iterator end = A.end();
for(it = A.begin(); it != end; ++it) {
if(*it == b)
return true;
}
return false;
}
template <typename T>
void uniqueRows1(const::std::vector<std::vector<T> > &A,
std::vector<std::vector<T> > &ret) {
typename std::deque<std::vector<T> > ulist;
typename std::vector<std::vector<T> >::const_iterator it = A.begin();
const typename std::vector<std::vector<T> >::const_iterator end = A.end();
ulist.push_back(*it);
for(++it; it != end; ++it) {
if(!isInList(ulist,*it)) {
ulist.push_back(*it);
}
}
ret.reserve(ulist.size());
for(size_t i = 0; i != ulist.size(); ++i) {
ret.push_back(ulist[i]);
}
}
+1 - notez que ma solution sera également plus rapide lorsqu'il y a peu d'éléments dupliqués, même pour les grandes entrées. Hashing nécessite l'examen de l'ensemble du vecteur interne tandis que les comparaisons utilisées dans 'sort' ne compareront souvent que les premiers éléments. –
très bon point. 'reso' devrait profiler les deux implémentations pour voir lequel correspond le mieux à son application. – vladr
Merci pour l'entrée Vlad. Malheureusement, mon application a des entrées de deux membres finaux: les vecteurs longs avec beaucoup de valeurs répétées, ou les cas où les vecteurs longs ont presque zéro valeurs en double. Mes approches originales (et très naïves et non optimales) semblaient bien fonctionner pour beaucoup de valeurs dupliquées, mais elles explosaient quand il y avait beaucoup d'uniques.Je vais mettre en œuvre cela et jeter un oeil juste pour apprendre les techniques. Merci! – reso