代码之家  ›  专栏  ›  技术社区  ›  Zack Lee

如何合并两个条件相同的函数?

  •  5
  • Zack Lee  · 技术社区  · 6 年前

    我在想办法合并 addFruit() 具有 removeFruit()

    它们都使用相同的条件,但最后的函数调用不同。

    我的代码:

    #include <iostream>
    #include <string>
    #include <vector>
    
    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            if (str == "apples")
                addToVec(apples, count);
            else if (str == "oranges")
                addToVec(oranges, count);
            else if (str == "lemons")
                addToVec(lemons, count);
            else if (str == "melons")
                addToVec(melons, count);
            else if (str == "bananas")
                addToVec(bananas, count);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
        void removeFruit(const std::string &str)
        {
            if (str == "apples")
                removeFromVec(apples);
            else if (str == "oranges")
                removeFromVec(oranges);
            else if (str == "lemons")
                removeFromVec(lemons);
            else if (str == "melons")
                removeFromVec(melons);
            else if (str == "bananas")
                removeFromVec(bananas);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
    private:
        void addToVec(std::vector<int> &vec, int count)
        {
            vec.push_back(count);
        }
        void removeFromVec(std::vector<int> &vec)
        {
            vec.pop_back();
        }
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
    };
    

    有什么聪明的方法可以很好地合并这两个函数,这样我就可以减少代码了?

    9 回复  |  直到 6 年前
        1
  •  6
  •   Korni    6 年前

    determineTargetVector(const std::string &str) 它返回对应的向量,在其中插入/删除元素,因此没有多余的条件。另外,对于每个函数只有一个单一的响应也是很好的。

    std::vector<int> *determineTargetVector(const std::string &str)
    {
        if (str == "apples")
            return &apples;
        else if (str == "oranges")
            return &oranges;
        else if (str == "lemons")
            .
            .
            .
        else
            //something invalid, to check for in superior function
            return nullptr;
    }
    
        2
  •  3
  •   πάντα ῥεῖ    6 年前

    最简单的解决方法可能是使用 std::map 对于这些向量:

    std::map<std::string,std::vector<int>> fruitVecs;
    

    "apples" "oranges" , "bananas" 等。

    因此,您可以轻松地通过地图访问任何操作的对应向量。

        3
  •  2
  •   Rizwan    6 年前

    可以使用选择要使用的向量然后执行操作的代码:

    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            auto vec = selectVector(str);
            if(vec != nullptr)
                addToVec(*vec, count);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
        void removeFruit(const std::string &str)
        {
            auto vec = selectVector(str);
            if(vec != nullptr)
                removeFromVec(*vec);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
    private:
    
        std::vector<int> *selectVector(const std::string &str)
        {
            if (str == "apples")
                return &apples;
            else if (str == "oranges")
                return &oranges;
            else if (str == "lemons")
                return &lemons;
            else if (str == "melons")
                return &melons;
            else if (str == "bananas")
                return &bananas;
            else
                return nullptr;
        }
    
        void addToVec(std::vector<int> &vec, int count)
        {
            vec.push_back(count);
        }
        void removeFromVec(std::vector<int> &vec)
        {
            vec.pop_back();
        }
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
    };
    
        4
  •  2
  •   Manthan Tilva    6 年前

    #include <iostream>
    #include <string>
    #include <vector>
    #include <map>
    
    class MyClass
    {
    public:
        MyClass()
        {
            allowedFruits["apples"] = {};
            allowedFruits["oranges"] = {};
            allowedFruits["lemons"] = {};
            allowedFruits["melons"] = {};
            allowedFruits["bananas"] = {};
        }
        void addFruit(const std::string &str, int count)
        {
            auto it = allowedFruits.find(str);
            if(it != MyClass::allowedFruits.end()){
                it->second.push_back(count);
            }
            else {
                std::cout << "Unknown Fruit : " << str << '\n';
            }
        }
        void removeFruit(const std::string &str)
        {
            auto it = allowedFruits.find(str);
            if(it != allowedFruits.end()){
                // my be some check here
                it->second.pop_back();
            }
            else {
                std::cout << "Unknown Fruit : " << str << '\n';
            }
        }
    private:
        std::map<std::string,std::vector<int>> allowedFruits;
    };
    
        5
  •  1
  •   463035818_is_not_an_ai    6 年前

    在不改变界面的情况下,您可以这样做:

    std::vector<int>& pickVector(std::string str) {
        // put all the switch here and return a reference to the correct vector
    }
    
    void addFruit(const std::string &str, int count)
    {
       addToVec(pickVector(str),count);
    }
    
        6
  •  1
  •   dkg    6 年前

    #include <iostream>
    #include <string>
    #include <vector>
    #include <functional>
    
    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            searchAndApplyHelper(str, std::bind(&MyClass::addToVec, *this, std::placeholders::_1, count));
        }
        void removeFruit(const std::string &str)
        {
            searchAndApplyHelper(str, std::bind(&MyClass::removeFromVec, *this, std::placeholders::_1));
        }
    
    private:
    
        template <class Func>
        void searchAndApplyHelper(const std::string str, Func f)
        {
            if (str == "apples")
                f(apples);
            else if (str == "oranges")
                f(oranges);
            else if (str == "lemons")
                f(lemons);
            else if (str == "melons")
                f(melons);
            else if (str == "bananas")
                f(bananas);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
    
        void addToVec(std::vector<int> &vec, int count)
        {
            vec.push_back(count);
        }
        void removeFromVec(std::vector<int> &vec)
        {
            vec.pop_back();
        }
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
    };
    

    我是用模板做的,但你可以用 std::function

        7
  •  1
  •   Leubh    5 年前

    我会这样做:

    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            doToFruit(str, [&](std::vector<int> &vec){ addToVec(vec, count); });
        }
        void removeFruit(const std::string &str)
        {
            doToFruit(str, [&](std::vector<int> &vec){ removeFromVec(vec); });
        }
    private:
        template<typename Callable>
        void doToFruit(const std::string &str, const Callable &func)
        {
            std::pair<const char*, std::vector<int>&> fruits[] = {
                {"apple", apples}, {"oranges", oranges}, {"lemons", lemons},
                {"melons", melons}, {"bananas", bananas}
            };
            for (auto i : fruits)
                if (str == i.first)
                    return func(i.second);
            std::cout << "Unknown Fruit : " << str << '\n';
        }
        void addToVec(std::vector<int> &vec, int count)
        {
            vec.push_back(count);
        }
        void removeFromVec(std::vector<int> &vec)
        {
            vec.pop_back();
        }
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
    };
    

    pointer to members 如果您想要更好的性能:

    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            doToFruit(str, [&](std::vector<int> &vec){ addToVec(vec, count); });
        }
        void removeFruit(const std::string &str)
        {
            doToFruit(str, [&](std::vector<int> &vec){ removeFromVec(vec); });
        }
    private:
        template<typename Callable>
        void doToFruit(const std::string &str, const Callable &func)
        {
            auto iFound = fruits.find(str);
            if (iFound != fruits.end())
                return func(this->*(iFound->second));
            std::cout << "Unknown Fruit : " << str << '\n';
        }
        void addToVec(std::vector<int> &vec, int count)
        {
            vec.push_back(count);
        }
        void removeFromVec(std::vector<int> &vec)
        {
            vec.pop_back();
        }
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
        static std::unordered_map<std::string, std::vector<int> MyClass::*> fruits;
    };
    
    std::unordered_map<std::string, std::vector<int> MyClass::*> MyClass::fruits = {
        {"apple", &MyClass::apples}, {"oranges", &MyClass::oranges},
        {"lemons", &MyClass::lemons}, {"melons", &MyClass::melons},
        {"bananas", &MyClass::bananas}
    };
    
        8
  •  0
  •   Nick is tired Boris    6 年前

    使用C++ 17可以使用可选参数:

    void addRemoveFruit(const std::string &str, std::optional<int> count = std::nullopt)
    {
        if (str == "apples")
            addRemoveVec(apples, count);
        else if (str == "oranges")
            addRemoveVec(oranges, count);
        else if (str == "lemons")
            addRemoveVec(lemons, count);
        else if (str == "melons")
            addRemoveVec(melons, count);
        else if (str == "bananas")
            addRemoveVec(bananas, count);
        else
            std::cout << "Unknown Fruit : " << str << '\n';
    }
    

    以及:

    void addRemoveVec(std::vector<int> &vec, std::optional<int> count = std::nullopt)
    {
        if(count.has_value()) {
            vec.push_back(count.value());
        } else {
            vec.pop_back();
        }
    }
    

    addFruit / removeFruit addRemoveFruit 无需更改传递的参数。

        9
  •  -1
  •   Max Vollmer    6 年前

    为了坚持多个不同向量的模式,我建议使用决定方法的内部枚举,而向量的选择可以在一个地方完成:

    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            addOrRemoveFruit(str, count, Method::ADD);
        }
        void removeFruit(const std::string &str)
        {
            addOrRemoveFruit(str, 0, Method::REMOVE);
        }
    
    private:
        enum class Method
        {
            ADD,
            REMOVE
        };
    
        void addOrRemoveFruit(const std::string &str, int count, Method method)
        {
            if (str == "apples")
                addOrRemoveFruitImpl(apples, count, method);
            else if (str == "oranges")
                addOrRemoveFruitImpl(oranges, count, method);
            else if (str == "lemons")
                addOrRemoveFruitImpl(lemons, count, method);
            else if (str == "melons")
                addOrRemoveFruitImpl(melons, count, method);
            else if (str == "bananas")
                addOrRemoveFruitImpl(bananas, count, method);
            else
                std::cout << "Unknown Fruit : " << str << '\n';
        }
    
        void addOrRemoveFruitImpl(std::vector<int> &vec, int count, Method method)
        {
            if (method == Method::ADD)
                 vec.push_back(count);
            else
                 vec.pop_back();
        }
    
        std::vector<int> apples;
        std::vector<int> oranges;
        std::vector<int> lemons;
        std::vector<int> melons;
        std::vector<int> bananas;
    };
    

    class MyClass
    {
    public:
        void addFruit(const std::string &str, int count)
        {
            fruits[str].push_back(count);
        }
        void removeFruit(const std::string &str)
        {
            if (fruits.count(str) > 0)
                fruits[str].pop_back();
        }
    
    private:
        std::unordered_map<std::string, std::vector<int>> fruits;
    };