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

发布于 2024-09-07 09:28:54 字数 824 浏览 2 评论 0原文

例程示例:

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

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

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

还有哪些其他方法可以做到这一点?

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

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

问题的目的是发现/找到我还不知道的语言特性/编程技术。我怀疑可能存在类似于 for_each 的适用构造/模板/函数/技术,并且了解该技术可能会有用。这是询问的主要原因。

有想法吗?

Example routine:

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

Routine's purpose is (obviously) to find a value within an array of elements, based on element's member variable, where comparing member variable with external "key" is search criteria.

One way to do it is to iterate through array in loop. Another is to use some kind of "map" class (std::map, some kind of vector sorted values + binarySearch, etc, etc). It is also possible to make a class for std::find or for std::for_each and use it to "wrap" the iteration loop.

What are other ways to do that?

I'm looking for alternative ways/techniques to extract the required element.
Ideally - I'm looking for a language construct, or a template "combo", or a programming pattern I don't know of that would collapse entire loop or entire function into one statement. Preferably using standard C++/STL features (no C++0x, until it becomes a new standard) AND without having to write additional helper classes (i.e. if helper classes exist, they should be generated from existing templates).

I.e. something like std::find where comparison is based on class member variable, and a variable is extracted using standard template function, or if variable (the one compared against "key"("name")) in example can be selected as parameter.

The purpose of the question is to discover/find language feature/programming technique I don't know yet. I suspect that there may be an applicable construct/tempalte/function/technique similar to for_each, and knowing this technique may be useful. Which is the main reason for asking.

Ideas?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(5

转身泪倾城 2024-09-14 09:28:54

如果您有权访问 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);
}

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

If you have access to Boost or another tr1 implementation, you can use bind to do this:

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

Caveat: I suspect many would admit that this is shorter, but claim it fails on the more elegant/simpler criteria.

旧梦荧光笔 2024-09-14 09:28:54

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

Sure looks like a case for std::find_if -- as the predicate, you could use e.g. a suitable bind1st. I'm reluctant to say more as this smacks of homework a lot...;-).

眼趣 2024-09-14 09:28:54

为什么是5行? Clean 没有附有编号。事实上,干净的代码可能会在实用程序类中占用更多行,然后可以反复重用。不要不必要地限制自己。

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

Why 5 lines? Clean doesn't have a number attached to it. In fact, clean code might take more lines in the utility classes, which can then be reused over and over. Don't restrict yourself unnecessarily.

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

Then:

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

Within restriction:

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

Then:

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 has ranged-based for-loops, which I think would make the most elegant solution:

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

    return 0;
}
时间你老了 2024-09-14 09:28:54

您可能需要使用 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;}

You would probably need to use STL map. It gives you possibility to get the element using keys. Your key would be the name of armature.

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

EDIT: :D

one liner 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;}
寒江雪… 2024-09-14 09:28:54

天啊,你用的是 _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 引用。

Holy shiz, you're using _stricmp? FAIL. Also, you didn't actually tell us the type of the vectors or any of the variables involved, so this is just guesswork.

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

Ultimately, if you need this, you should put the armatures or pointers to them in a std::map. A vector is the wrong container if you're searching into it, they're best for when the collection is what's important rather than any finding behaviour.

Edited to use a std::string reference.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文