2011-09-26 1 views
0

Je sais que si j'ai un vector<int> je peux exécuter des algorithmes sur elle comme ceci:Est-il possible d'exécuter des algorithmes standard sur le vecteur <MyType> d'une manière élégante?

int max = *max_element(myints.begin(), myints.end()); 

Mais si j'ai un vector<MyStruct> où l'un des champs de la struct est un entier. Existe-t-il une manière élégante et élégante d'exécuter un algorithme sur les entiers de toutes mes structures?

+0

Cela dépend de votre définition de "élégant" et si vous avez un support C++ 11. –

+0

Que voulez-vous dire par "élégant", et pouvez-vous utiliser boost.phoenix et/ou C++ 11 lamdbas? – PlasmaHH

+3

Il n'y a pas d'algorithmes 'int' en C++ (STL), les algorithmes sont génériques. – agibalov

Répondre

11

Fournir un comparateur à max_element:

MyStruct max = *max_element(v.begin(), v.end(), 
    [](const MyStruct & lhs, const MyStruct & rhs) { return lhs.theInt < rhs.theInt; }); 

Si votre compilateur ne supporte pas encore lambdas, vous devrez écrire une fonction distincte ou la fonction classe d'objet.

Sinon, si vous surchargez operator< pour votre classe pour faire ce même comparaison, alors vous pouvez simplement faire ceci:

MyStruct max = *max_element(v.begin(), v.end()); 
+0

C'est exactement ce que je voulais, merci! – Benj

1

Pour les structures, vous pouvez définir une fonction ou un objet de comparaison. Vous pouvez également définir l'opérateur < pour votre structure. Voici un example.

+0

Je pourrais le faire si je voulais seulement faire un type d'algorithme sur la structure. Cependant, dans mon cas, la structure a 20 champs qui sont ints/floats/doubles et je veux produire des statistiques basées sur ces champs. Évidemment je pourrais écrire quelque chose pour faire ceci en faisant une boucle mais je voulais voir s'il y avait une manière plus STL de le faire ... – Benj

+0

@Benj: Que écrire la même chose comme fonction libre ou foncteur. Tous les algorithmes prennent l'opérateur approprié comme dernier argument facultatif. –

+0

@Benj: Le 'max_element' trouve le maximum de la façon que vous le définissez (c'est-à-dire en utilisant n'importe quel comparateur que vous fournissez). Si vous avez besoin de trouver le maximum de plusieurs champs différents, vous devrez définir plusieurs comparateurs différents. Vous devez dire à la fonction en quelque sorte ce que vous entendez par max pour que cela fonctionne, il n'y a pas moyen de contourner cela. Ceci est fondamentalement vrai pour toute autre fonction basée sur la comparaison dans le STL. – MAK

4

Cela dépend de votre définition de « élégante » est, mais oui, cela peut être terminé. En fait, de nombreuses façons différentes.

En standard C++, vous pouvez utiliser un Functor:

#include <algorithm> 
#include <vector> 
#include <functional> 
using namespace std; 

class Gizmo 
{ 
public: 
    int n_; 
}; 

class BiggestGizmo : public std::binary_function<bool, Gizmo, Gizmo> 
{ 
public: 
    bool operator()(const Gizmo& lhs, const Gizmo& rhs) const 
    { 
     return lhs.n_ > rhs.n_; 
    } 
}; 

int main() 
{ 
    typedef vector<Gizmo> Gizmos; 
    Gizmos gizmos; 
    Gizmos::const_iterator it = max_element(gizmos.begin(), gizmos.end(), BiggestGizmo()); 
} 

En C++ 0X, vous pouvez utiliser un Lambda:

#include <algorithm> 
#include <vector> 
using namespace std; 

class Gizmo 
{ 
public: 
    int n_; 
}; 

int main() 
{ 
    typedef vector<Gizmo> Gizmos; 
    Gizmos gizmos; 
    Gizmos::const_iterator it = max_element(gizmos.begin(), gizmos.end(), [](const Gizmo& lhs, const Gizmo& rhs) -> bool 
    { 
     return lhs.n_ > rhs.n_; 
    }); 
} 
0

Comme vous l'avez dit dans l'un des commentaires que vous avez beaucoup de membres de la classe et veulent aborder chacun individuellement dans les algorithmes. Vous vous retrouvez avec différentes possibilités

  • lambdas partout (soit Phoenix ou 11 C++)
  • foncteurs pour tous les cas
  • fonctions membres pour tous les cas

Je préfère la dernière deux solutions seulement si j'avais besoin de répéter le lambdas dans différents endroits (ou si je devais utiliser Phoenix, mais c'est juste une chose personnelle).

struct Foo { 
    int a; 
    int b; 
    bool less_than_by_a(const Foo&) const; 
    bool less_than_by_b(const Foo&) const; 
}; 

std::max_element(begin, end, std::mem_fun_ref(&Foo::less_than_by_a)); 
std::max_element(begin, end, std::mem_fun_ref(&Foo::less_than_by_b)); 
2

Une autre option dans le mélange: vous pourriez écrire une classe itérateur de votre propre dont les types référence et la valeur sont int& et int, mais qui agit sur le dessus d'un itérateur avec le type de référence MyStruct&, l'accès à ce domaine .

Il est un peu plus de travail que la simple fourniture d'un comparateur supplémentaire pour max_element, mais si vous le faites une fois, vous avez fait pour tous algorithmes, pas seulement ceux qui agissent par l'intermédiaire d'un comparateur. Si vous pouvez l'utiliser, boost::transform_iterator gérera le passe-partout pour vous.

boost::transform_iterator ne vous permet pas de récupérer l'itérateur sous-jacent d'une instance, mais dans le cas de vector cela n'a pas trop d'importance car c'est un accès aléatoire, donc il est efficace de calculer la distance et de l'appliquer à la begin() itérateur.

+0

+1 pour intéressant. Mais par curiosité, quel genre d'algorithmes aviez-vous en tête? Tout spécifiquement? –

+1

@Benjamin: Tout ce qui n'utilise pas de comparateur, vraiment. Supposons que vous vouliez exécuter 'std :: accumulate' pour additionner les entiers dans toutes les structures du vecteur. Si vous avez déjà écrit le comparateur comme dans votre réponse, alors inutile, vous devez toujours écrire une fonction d'addition (ou un 'opérateur +' pour 'mystruct', le cas échéant). Si vous avez déjà un adaptateur d'itérateur, vous pouvez utiliser le même pour 'accumulate' et' max_element'. –

+0

Une alternative vraiment intéressante à l'approche du comparateur, merci :-) – Benj

Questions connexes