J'aimerais pouvoir écrire quelque chose comme
char f(char);
vector<char> bar;
vector<char> foo = map(f, bar);
El transform
semble être similaire, mais elle ne génère pas automatiquement la taille de la collection résultante.
J'aimerais pouvoir écrire quelque chose comme
char f(char);
vector<char> bar;
vector<char> foo = map(f, bar);
El transform
semble être similaire, mais elle ne génère pas automatiquement la taille de la collection résultante.
Cette question a été posée avant l'entrée en vigueur de la norme C++11... aujourd'hui nous avons std::transform()
comme l'équivalent (laid) d'une "carte" de programmation fonctionnelle. Voici comment l'utiliser :
auto f(char) -> char; // or if you like: char f(char)
vector<char> bar;
vector<char> foo;
// ... initialize bar somehow ...
std::transform(bar.begin(), bar.end(), std::back_inserter(foo), f);
Pour que cela fonctionne, vous aurez besoin des observations suivantes :
map
La fonction doit pas faire le travail. Au lieu de cela, il devrait enregistrer ses arguments dans un objet temporaire (dans votre cas, ce serait une instance de class map::result<char(*)(char), vector<char> >
)map::result
temporaire devrait avoir un template <typename T> operator T
conversion.map::result
est affecté à un std::vector<char>
cette conversion est la seule viable.class map::result<char(*)(char), vector<char> >::operator vector<char>
vous avez le type d'entrée et de retour, et la fonction de mappage. À ce stade, vous pouvez effectivement transformer les entrées.<edit>
template<typename CONT, typename FUNC>
class mapresult {
CONT const& in;
FUNC f;
public:
template<typename RESULT> RESULT to() const
{
RESULT out;
for (auto const& e : in) { out.push_back(f(e)); }
return out;
}
template<typename RESULT> operator RESULT() const
{
return this->to<RESULT>();
}
mapresult(CONT const& in, FUNC f) : in(in), f(std::move(f)) { }
};
template<typename CONT, typename FUNC>
auto map(CONT const& in, FUNC f) -> mapresult<CONT, FUNC>
{
return mapresult<CONT, FUNC>(in, f);
}
using namespace std;
char foo(char c) { return c | ('A' ^ 'a'); }
std::string in = "Test";
int main(int argc, char* argv[])
{
string out = map(in, &foo);
cout << out << endl;
char replace = 'e';
cout << map(in, [replace](char c){return c == replace ? '?' : c; }).to<string>();
}
El std::transform
fait le travail, mais n'est pas performant dans certains cas. Je suggérerais d'utiliser une while
boucle et en réservant la taille à l'avance. Cette fonction peut facilement être modifiée pour être utilisée avec des chaînes de caractères ou n'importe quoi d'autre.
template<typename T, typename C>
std::vector<T> map(const std::vector<C> &array, auto iteratee) {
int index = -1;
int length = array.size();
std::vector<T> v(length);
while(++index < length) {
v[index] = iteratee(array[index], index);
}
return v;
}
Appeler la fonction où array
est le std::vector que vous souhaitez cartographier.
auto result = map<int, int>(array, [](int elem, int index) {
return elem + 10;
});
Carte de fonctionnement sur 100 000 000 avec std::transform
a pris ~6.15s
La version en boucle prend ~3.90s.
Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.