STL列表-如何通过对象字段查找列表元素

发布于 2024-09-02 04:24:53 字数 537 浏览 2 评论 0原文

我有一个列表:

list<Unit *> UnitCollection;

包含 Unit 对象,它有一个访问器,例如:

bool Unit::isUnit(string uCode)
{
    if(this->unitCode == uCode)
        return true;
    else
        return false;
}

如何通过 uCode 搜索我的 UnitCollection 列表并返回相应的元素(最好是和迭代器)。

在伪代码中,它看起来像这样:

for every item in my UnitCollection:
  if the unit.isUnit(someUnitIpass)
    do something
  else
    next unit

我已经查看了 find() 方法,但我不确定您是否可以传递布尔方法而不是搜索到的项目参数(如果这有意义)。

I have a list:

list<Unit *> UnitCollection;

containing Unit objects, which has an accessor like:

bool Unit::isUnit(string uCode)
{
    if(this->unitCode == uCode)
        return true;
    else
        return false;
}

How do I search my UnitCollection list by uCode and return the corresponding element (preferably and iterator).

In pseudo code it would look something like this:

for every item in my UnitCollection:
  if the unit.isUnit(someUnitIpass)
    do something
  else
    next unit

I have looked at the find() method, but i'm not sure you can pass a boolean method in instead of a searched item parameter if that makes sense.

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

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

发布评论

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

评论(4

葬花如无物 2024-09-09 04:24:53

首先,

您可以将访问器函数更改为更简单的形式。

return unitCode == uCode;

现在我们要为您提供的内容

您最好查找元素的位置,而不是其索引。从其索引获取元素是一个 O(n) 操作,而从其位置获取元素是一个 O(1) 操作。因此,借助 STL 以及 boost::bind() 的一点帮助:

#include <algorithm>
#include <boost/bind.hpp>

// ...
std::string uCode("uCode to search for");
std::list<Unit*>::iterator pos = std::find_if(unitCollection.begin(),
                                              unitCollection.end(),
                                              boost::bind(&Unit::isUnit,
                                                          _1, uCode));

STL 确实有 std::mem_fun(),它与 std 一起::bind2nd() 会给出相同的结果。问题是 mem_fun() 仅适用于不带参数的成员函数。另一方面,boost::bind() 功能更强大,并且确实很好地解决了这里的问题。你应该在下一个标准中期待它,它应该在弥赛亚到来后立即出现。

但如果你没有 Boost

如果你的项目中还没有 Boost 那么你真的真的应该安装它。如果说标准库是C++的妻子,那么Boost就是C++的年轻情人。他们应该都在那里,他们相处得很好。

话虽如此,您可以将函数提取到一个独立的函数对象中,正如 Peter 已经提到的:

struct has_uCode {
    has_uCode(cont std::string& uc) : uc(uc) { }
    bool operator()(Unit* u) const { return u->isUnit(uc); }
private:
    std::string uc;
};

然后,您可以像这样调用 std::find_if():

std::list<Unit*>::iterator pos = std::find_if(unitCollection.begin(),
                                              unitCollection.end(),
                                              has_uCode("this and that"));

还有一点性能考虑

还有一件事:我不知道 uCode 是什么样子,但如果它们很大,那么您可以通过维护这些字符串的哈希值来加快速度,以便在搜索谓词中只比较哈希值。哈希值可能是常规整数:比较整数非常快。

还有一件事:如果您经常运行此搜索过程,您可能还会考虑更改容器类型,因为这确实是一个昂贵的过程:按照列表长度的顺序。

An Insignificant Comment First

You might change your accessor function to the simpler form

return unitCode == uCode;

Now To What We're Here For

You're better off looking for the position of the element rather than its index. Getting an element from its index is an O(n) operation, whereas getting an element from its position is an O(1) operation. So, with the STL and a little help from boost::bind():

#include <algorithm>
#include <boost/bind.hpp>

// ...
std::string uCode("uCode to search for");
std::list<Unit*>::iterator pos = std::find_if(unitCollection.begin(),
                                              unitCollection.end(),
                                              boost::bind(&Unit::isUnit,
                                                          _1, uCode));

The STL does have std::mem_fun(), which, along with std::bind2nd() would give the same result. The problem is that mem_fun() only works with member functions that take no arguments. boost::bind() on the other hand is much more powerful, and does solve the problem here very nicely. You should expect it in the next standard, which should be here immediately after the Messiah arrives.

But If You Don't Have Boost

If don't already have boost in your project then you really, really should install it. If the standard library is C++'s wife, then Boost is C++'s young lover. They should both be there, they get along fine.

Having said that, you can extract the function into a standalone function object as Peter mentioned already:

struct has_uCode {
    has_uCode(cont std::string& uc) : uc(uc) { }
    bool operator()(Unit* u) const { return u->isUnit(uc); }
private:
    std::string uc;
};

Then, you can call std::find_if() like so:

std::list<Unit*>::iterator pos = std::find_if(unitCollection.begin(),
                                              unitCollection.end(),
                                              has_uCode("this and that"));

And a Little Bit of Performance Consideration

One more thing: I don't know how uCode's look like, but if they're big then you might speed things up by maintaing hashes of these strings so that in your search predicate you only compare the hashes. The hashes might be regular integers: comparing integers is pretty fast.

One more one-more-thing: If you run this search procedure often you might also consider changing your container type, because this really is an expensive procedure: in the order of the list's length.

逐鹿 2024-09-09 04:24:53

您可以按照 jpalecek 的建议查看 find_if ,然后使用 distance 查找 find_if 返回的迭代器与 UnitCollection.begin() 之间的距离,该距离应该是列表中元素的索引。

至于谓词,您可以编写一个像这样的函数对象:

struct predicate
{
    predicate( const std::string &uCode ) : uCode_(uCode) {}

    bool operator() ( Unit *u )
    {
        return u->isUnit( uCode_ )
    }
private:
    std::string uCode_;
};

然后像这样使用它:

predicate pred("uCode");
std::list<Unit*>::iterator i;
i = std::find_if( UnitCollection.begin(), UnitCollection.end(), pred );

或者至少我认为这是一种方法。

You could have a look at find_if as jpalecek suggests, and then use distance to find the distance between the iterator returned from find_if and UnitCollection.begin(), and that distance should be the index of the element in the list.

And as for the predicate, you could write a function object like this:

struct predicate
{
    predicate( const std::string &uCode ) : uCode_(uCode) {}

    bool operator() ( Unit *u )
    {
        return u->isUnit( uCode_ )
    }
private:
    std::string uCode_;
};

And then use it like this:

predicate pred("uCode");
std::list<Unit*>::iterator i;
i = std::find_if( UnitCollection.begin(), UnitCollection.end(), pred );

Or at least I think that would be a way to do it.

白昼 2024-09-09 04:24:53

您的谓词可能类似于:

struct unit_predicate {
    unit_predicate(const string& s): str(s) {}
    bool operator()(const Unit* unit) const {
        return unit->isUnit(str);
    }
    const string& str;
};

UnitCollection::const_iterator unit = std::find_if(units.begin(), units.end(), unit_predicate("Some Unit"));

其他一些注释:

您的 isUnit 函数最好通过 (const) 引用获取字符串,以避免不必要的复制。

你说你想返回一个项目的索引;这对于链接列表通常是不明智的,因为您无法通过索引获取项目。如果您想通过索引处理它们,也许 std::vector 对您更有用。

Your predicate might look something like:

struct unit_predicate {
    unit_predicate(const string& s): str(s) {}
    bool operator()(const Unit* unit) const {
        return unit->isUnit(str);
    }
    const string& str;
};

UnitCollection::const_iterator unit = std::find_if(units.begin(), units.end(), unit_predicate("Some Unit"));

A couple of other comments:

Your isUnit function would be better to take the string by (const) reference to avoid unnecessary copies.

You say you'd like to return the index of an item; that isn't normally sensible for linked lists, because you can't get items back by index. If you want to deal with them by index, maybe std::vector would be more useful to you.

任性一次 2024-09-09 04:24:53

看看find_if

如果您可以使用 boost,则可以将其与 boost::lambda 一起使用。

namespace bl=boost::lambda;
std::find_if(...begin... , ...end... , bl::bind(&Unit::isUnit, *bl::_1, "code"))

或者你可以编写自己的函子。

struct isUnitor // : public std::unary_function<Unit*, bool> -- this is only needed for the negation below
{
  string arg;
  isUnitor(const string& s) : arg(s) {}
  bool operator()(Unit* u) const { return u->isUnit(arg); }
};

std::find_if(...begin... , ...end... , isUnitor("code"))

或者,如果您想要索引(对于否定,请查看 此处):

std::count_if(...begin... , ...end... , not1(isUnitor("code")))

Have a look at find_if.

If you can use boost, you can use it with boost::lambda.

namespace bl=boost::lambda;
std::find_if(...begin... , ...end... , bl::bind(&Unit::isUnit, *bl::_1, "code"))

or you can brew your own functor.

struct isUnitor // : public std::unary_function<Unit*, bool> -- this is only needed for the negation below
{
  string arg;
  isUnitor(const string& s) : arg(s) {}
  bool operator()(Unit* u) const { return u->isUnit(arg); }
};

std::find_if(...begin... , ...end... , isUnitor("code"))

or, if you want the index (for the negation, look here):

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