按成员值查找数组元素 - 什么是“for”loop / std :: map / Compare / for_each替代品?

时间:2010-06-27 17:58:14

标签: c++ stl

示例例程:

const Armature* SceneFile::findArmature(const Str& name){
    for (int i = 0; i < (int)armatures.size(); i++)
        if (name == armatures[i].name)
            return &armatures[i];
    return 0;
}

例程的目的是(显然)根据元素的成员变量在元素数组中查找值,其中比较成员变量和外部“键”是搜索条件。

一种方法是循环遍历数组。另一种是使用某种“map”类(std :: map,某种矢量排序值+ binarySearch等)。也可以为std :: find或std :: for_each创建一个类,并使用它来“包装”迭代循环。

有什么其他方法可以做到这一点?

我正在寻找提取所需元素的替代方法/技术。 理想情况下 - 我正在寻找语言结构,或模板“组合”,或者我不知道的编程模式会将整个循环或整个函数折叠成一个语句。最好使用标准的C ++ / STL特性(没有C ++ 0x,直到它成为新标准)并且不必编写额外的辅助类(即,如果存在辅助类,则应该从现有模板生成它们)。

即。类似于std :: find的地方比较基于类成员变量,并且使用标准模板函数提取变量,或者如果可以选择变量(与“key”(“name”)比较的变量)作为参数。

问题的目的是发现/找到我还不知道的语言特征/编程技术。我怀疑可能是一个类似于for_each的适用的构造/ tempalte / function /技术,并且知道这种技术可能很有用。这是询问的主要原因。

想法?

5 个答案:

答案 0 :(得分:2)

如果您有权访问Boost或其他tr1实现,则可以使用bind来执行此操作:

const Armature * SceneFile::findArmature(const char * name) {
  find_if(armatures.begin(), armatures.end(),
    bind(_stricmp, name, bind(&string::c_str, bind(&Armature::name, _1))) == 0);
}

警告:我怀疑很多人会承认这会更短,但声称它在更优雅/更简单的标准上失败了。

答案 1 :(得分:1)

当然看起来像std::find_if的情况 - 作为谓词,你可以使用例如一个合适的bind1st。我不愿意多说这些作业很多 ...; - )。

答案 2 :(得分:1)

为什么5行?清洁没有附加数字。事实上,干净的代码可能会在实用程序类中占用更多行,然后可以反复使用它们。不要不必要地限制自己。

class by_name
{
public:
    by_name(const std::string& pName) :
    mName(pName)
    {}

    template <typename T>
    bool operator()(const T& pX)
    {
        return pX.name == pName;
    }

private:
    std::string mName;
};

然后:

const Armature* SceneFile::findArmature(const char* name)
{
    // whatever the iterator type name is
    auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
    return iter == armatures.end() ? 0 : &(*iter);
}

在限制范围内:

class by_name { public: by_name(const std::string& pName) : mName(pName) {} template <typename T> bool operator()(const T& pX) { return pX.name == pName; } private: std::string mName; };

然后:

const Armature* SceneFile::findArmature(const char* name)
{
    // whatever the iterator type name is
    auto iter = std::find_if(armatures.begin(), armatures.end(), by_name(name));
    return iter == armatures.end() ? 0 : &(*iter);
}

:)


C ++ 0x有基于范围的for循环,我认为这将是最优雅的解决方案:

const Armature* SceneFile::findArmature(const std::string& pName) const
{
    for (auto a : armatures)
    {
        if (a.name = pName) return &a;
    }

    return 0;
}

答案 3 :(得分:0)

您可能需要使用STL地图。它使您可以使用获取元素。你的钥匙就是电枢的名字。

http://www.cplusplus.com/reference/stl/map/

编辑:: D

一个班轮B - )

const Armature* SceneFile::findArmature(const Str& name){for (int i = 0; i < (int)armatures.size(); i++) if(name == armatures[i].name) return &armatures[i]; return 0;}

答案 4 :(得分:-4)

神圣的shiz,你在使用_stricmp?失败。另外,你实际上没有告诉我们矢量的类型或涉及的任何变量,所以这只是猜测。

const Armature* SceneFile::findArmature(const std::string& lols) {
    for(auto it = armatures.begin(); it != armatures.end(); it++) {
        if (boost::iequals(lols, (*it).name))
            return &(*it);
    return NULL;
}

最终,如果你需要这个,你应该在std :: map中放置它们的骨架或指针。如果你正在搜索它,它就是一个错误的容器,当收集是重要的而不是任何发现行为时,它们是最好的。

编辑使用std :: string引用。