我有一个类型为:
的stl地图map<Object*, baseObject*>
其中
class baseObject{
int ID;
//other stuff
};
如果我想返回一个对象列表(std :: list&lt; Object *&gt;),那么按照baseObject.ID的顺序对它进行排序的最佳方法是什么?
我只是在寻找每一个数字或什么?我宁愿不将地图更改为增强地图,虽然我不一定反对做一些像
这样的返回函数中包含的内容。GetObjectList(std::list<Object*> &objects)
{
//sort the map into the list
}
编辑:也许我应该迭代并将obj-&gt; baseobj复制到baseobj.ID-&gt; obj的地图中?
答案 0 :(得分:2)
我要做的是先将密钥(因为你只想将它们返回)解压缩到一个向量中,然后对其进行排序:
std::vector<baseObject*> out;
std::transform(myMap.begin(), myMap.end(), std::back_inserter(out), [](std::pair<Object*, baseObject*> p) { return p.first; });
std::sort(out.begin(), out.end(), [&myMap](baseObject* lhs, baseObject* rhs) { return myMap[lhs].componentID < myMap[rhs].componentID; });
如果您的编译器不支持lambdas,只需将它们重写为自由函数或函数对象。我只是简单地使用lambdas。
为了表现,我最初可能reserve
在矢量中有足够的空间,而不是让它逐渐扩展。
(另请注意,我还没有测试过代码,所以可能需要一点点摆弄)
另外,我不知道这个地图应该代表什么,但是拿着一个地图,其中键和值类型都是指针真的设置我的“坏C ++”感觉刺痛。它闻到了手动内存管理和混乱(或不存在)所有权语义。
您提到在list
中获得输出,但vector
几乎肯定是性能更好的选项,所以我使用了它。 list
更可取的唯一情况是,当你无意迭代它时,如果你需要保证指针和迭代器在修改列表后保持有效。
答案 1 :(得分:1)
我认为你会做得很好:
GetObjectList(std::list<Object*> &objects)
{
std::vector <Object*> vec;
vec.reserve(map.size());
for(auto it = map.begin(), it_end = map.end(); it != it_end; ++it)
vec.push_back(it->second);
std::sort(vec.begin(), vec.end(), [](Object* a, Object* b) { return a->ID < b->ID; });
objects.assign(vec.begin(), vec.end());
}
答案 2 :(得分:1)
首先,我不会使用std::list
,而是使用std::vector
。现在,就特殊问题而言,您需要执行两项操作:生成容器,按照您的标准对其进行排序。
// Extract the data:
std::vector<Object*> v;
v.reserve( m.size() );
std::transform( m.begin(), m.end(),
std::back_inserter(v),
[]( const map<Object*, baseObject*>::value_type& v ) {
return v.first;
} );
// Order according to the values in the map
std::sort( v.begin(), v.end(),
[&m]( Object* lhs, Object* rhs ) {
return m[lhs]->id < m[rhs]->id;
} );
如果没有C ++ 11,您将需要创建仿函数而不是lambdas,如果您坚持要返回std::list
,那么您应该使用std::list<>::sort( Comparator )
。请注意,这可能效率低下。如果性能是一个问题(在您开始工作并且您了解并且知道这确实是一个瓶颈之后),您可能需要考虑使用中间map<int,Object*>
:
std::map<int,Object*> mm;
for ( auto it = m.begin(); it != m.end(); ++it )
mm[ it->second->id ] = it->first;
}
std::vector<Object*> v;
v.reserve( mm.size() ); // mm might have less elements than m!
std::transform( mm.begin(), mm.end(),
std::back_inserter(v),
[]( const map<int, Object*>::value_type& v ) {
return v.second;
} );
同样,这可能比原始版本更快或更慢......个人资料。
答案 3 :(得分:1)
以下是如何执行您所说的内容,“按照baseObject.ID的顺序对其进行排序”:
typedef std::map<Object*, baseObject*> MapType;
MapType mymap; // don't care how this is populated
// except that it must not contain null baseObject* values.
struct CompareByMappedId {
const MapType ↦
CompareByMappedId(const MapType &map) : map(map) {}
bool operator()(Object *lhs, Object *rhs) {
return map.find(lhs)->second->ID < map.find(rhs)->second->ID;
}
};
void GetObjectList(std::list<Object*> &objects) {
assert(objects.empty()); // pre-condition, or could clear it
// or for that matter return a list by value instead.
// copy keys into list
for (MapType::const_iterator it = mymap.begin(); it != mymap.end(); ++it) {
objects.push_back(it->first);
}
// sort the list
objects.sort(CompareByMappedId(mymap));
}
这并不是非常有效:它在地图中查找的内容比严格必要的更多,并且操纵std::list::sort
中的列表节点可能比std::sort
操纵随机时慢一点-access指针容器。但是,std::list
本身对于大多数用途来说效率不高,所以你预计设置它会很昂贵。
如果您需要进行优化,可以创建一对(int, Object*)
对的向量,这样您只需迭代一次地图,无需查看。对对进行排序,然后将每对的第二个元素放入列表中。这可能是一个不成熟的优化,但它在实践中是一个有效的技巧。
答案 4 :(得分:0)
我会创建一个新的地图,其中包含使用对象的组件ID的排序标准。从第一个地图填充第二个地图(只需迭代或std :: copy in)。然后,您可以使用迭代器按顺序读取此映射。
在插入使用向量或列表(log(n)时间而不是常量时间)方面略有开销,但它避免了在创建好的向量或列表后进行排序的需要。
此外,您稍后可以在程序中添加更多元素,并且无需借助即可维护其订单。
答案 5 :(得分:0)
我不确定我是否完全理解您要在地图中存储的内容,但也许look here
std :: map的第三个模板参数是一个较少的仿函数。也许您可以利用它来在插入时对存储在地图中的数据进行排序。然后它将是地图迭代器上的直接循环以填充列表