39 votes

Nom STL pour la fonction de programmation fonctionnelle "map".

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.

46voto

AraK Points 38702

Vous pouvez utiliser std::back_inserter sur <iterator> Bien qu'il soit plus efficace de fournir la taille à l'avant. Par exemple :

string str = "hello world!", result;
transform(str.begin(), str.end(), back_inserter(result), ::toupper);
// result == "HELLO WORLD!"

19voto

einpoklum Points 2893

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);

4voto

MSalters Points 74024

Pour que cela fonctionne, vous aurez besoin des observations suivantes :

  1. Pour rendre l'affectation efficace, le 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> > )
  2. Ce site map::result temporaire devrait avoir un template <typename T> operator T conversion.
  3. Lorsque le map::result est affecté à un std::vector<char> cette conversion est la seule viable.
  4. Dans l'opérateur de conversion 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>

Code

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);
}

Utilisez comme ça :

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>();
}

1voto

Don F Points 61

Vous pouvez imiter la syntaxe de la carte ci-dessus avec quelque chose comme

template<typename T, typename A>
T map(A(*f)(A), T & container) {
    T output;
    std::transform(container.begin(), container.end(), std::back_inserter(output), f);
    return output;
}

0voto

Ovior Points 83

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.com

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.

Powered by:

X