惯用C++;用于从std::map的最后n个元素创建std::vector Pd:创建STD的C++惯用方法是:从STD的最后n个元素::MAP?
我对保持向量的顺序不感兴趣 我可以复制元素,如下所示:惯用C++;用于从std::map的最后n个元素创建std::vector Pd:创建STD的C++惯用方法是:从STD的最后n个元素::MAP?,c++,vector,map,idioms,C++,Vector,Map,Idioms,我对保持向量的顺序不感兴趣 我可以复制元素,如下所示: std::map< double, MyType > m; size_t n = 3; std::vector< MyType > v; std::map< double, MyType >::iterator it = m.end(); while ( n-- ) { // assuming m.size() >= n it--;
std::map< double, MyType > m;
size_t n = 3;
std::vector< MyType > v;
std::map< double, MyType >::iterator it = m.end();
while ( n-- ) { // assuming m.size() >= n
it--;
v.push_back(it->second);
}
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
// I'm assuming it's ok to copy min(m.size(), n)
template <typename Iter>
Iter safe_advance(Iter begin, Iter const &end, int distance)
{
while(distance-- > 0 && begin != end)
++begin;
return begin;
}
void copy_last_n(map<double,int> const &m,
vector<int> &v, int n)
{
transform(m.rbegin(), safe_advance(m.rbegin(), m.rend(), n),
back_inserter(v),
[](map<double,int>::value_type const &val)
{
return val.second;
}
);
}
std::transform(map_first, map_last, std::back_inserter(vec), [](std::pair<double,MyType> p) { return p.second; });
std::mapm;
尺寸n=3;
std::vectorv;
std::map::迭代器it=m.end();
而(n--){//假设m.size()>=n
它--;
v、 向后推(它->秒);
}
但是,还有其他更惯用的方法吗?一种方法是对每个人使用一个简单的
:
map<int,double> m;
vector<double> v;
//Fill map
auto siter = m.end();
advance(siter, -3);
for_each(siter, m.end(), [&](pair<int,double> p) { v.push_back(p.second); });
map<int,double> m;
vector<double> v;
//Fill map
for_each(prev(m.end(), 3), m.end(),
[&](pair<int,double> p) { v.push_back(p.second); });
此外,如果要按相反顺序填充向量,可以使用:
for_each(m.rbegin(), next(m.rbegin(), 3),
[&](pair<int,double> p) { v.push_back(p.second); });
每个(m.rbegin(),下一个(m.rbegin(),3),
[&](对p){v.push_-back(p.second);};
反向操作:
assert(n <= m.size());
std::copy(m.rbegin(), m.rbegin()+n, std::back_inserter(v));
assert(nstd::copy
如果您希望复制类型不变,那么它将是合适的。然而,std::map::iterator\U type::value\U type
不是U
(您想要复制的类型),而是std::pair
(换句话说,取消对map迭代器的引用会产生一对键和值类型),所以原始副本不起作用
因此,我们需要复制元素,并在此过程中执行转换。这就是std::transform
的用途
为了方便起见,我将假设您的编译器支持C++11 lambda表达式和auto
关键字。如果不支持,它可以相当简单地重写为一个函子。但我们正在寻找大致如下的内容:
std::map< double, MyType > m;
size_t n = 3;
std::vector< MyType > v;
std::map< double, MyType >::iterator it = m.end();
while ( n-- ) { // assuming m.size() >= n
it--;
v.push_back(it->second);
}
#include <map>
#include <vector>
#include <algorithm>
#include <iterator>
using namespace std;
// I'm assuming it's ok to copy min(m.size(), n)
template <typename Iter>
Iter safe_advance(Iter begin, Iter const &end, int distance)
{
while(distance-- > 0 && begin != end)
++begin;
return begin;
}
void copy_last_n(map<double,int> const &m,
vector<int> &v, int n)
{
transform(m.rbegin(), safe_advance(m.rbegin(), m.rend(), n),
back_inserter(v),
[](map<double,int>::value_type const &val)
{
return val.second;
}
);
}
std::transform(map_first, map_last, std::back_inserter(vec), [](std::pair<double,MyType> p) { return p.second; });
这里唯一棘手的部分是映射迭代器是双向的,但不是随机访问,因此我们不能简单地说map.end()-n
。-
操作符没有定义。相反,我们必须使用std::next
(对于双向操作符,这需要线性而不是恒定的时间,但这是无法避免的)
(注意,我还没有尝试编译这段代码,因此可能需要进行一些调整)std::transform
将是最惯用的方法。您需要一个函数
对象:
这不是最有效的,但取决于n
及其所在位置
使用后,可能就足够了。如果您确实希望避免额外的复制,
等。(只有当n
通常比
(地图的大小),您必须做一些更有趣的事情:
std::vector<MyType>
extractLastN( std::map<double, MyType> const& source, ptrdiff_t n )
{
std::map<double, MyType>::const_iterator start
= source.size() <= n
? source.begin()
: std::prev( source.end(), n );
std::vector<MyType> results;
std::transform( start, source.end(),
std::back_inserter( results ),
Second<std::map<double, MyType>::value_type>() );
return results;
}
同样,如果您对标准库做了很多工作,您可能
您的工具箱中已经有了它。)这里有一个简单的Boost.Range版本:
#include <boost/range/iterator_range_core.hpp>
#include <boost/range/adaptor/map.hpp>
//#include <boost/range/adaptor/reversed.hpp> // comment in for 'reversed'
#include <map>
#include <vector>
struct X{};
int main(){
std::map<int, X> m;
unsigned n = 0;
auto vec(boost::copy_range<std::vector<X>>(
boost::make_iterator_range(m, m.size()-n, 0)
| boost::adaptors::map_values
//| boost::adaptors::reversed // comment in to copy in reverse order
));
}
#包括
#包括
//#将//注释包含在“已撤销”中
#包括
#包括
结构X{};
int main(){
std::map m;
无符号n=0;
自动矢量控制(boost::copy_范围(
boost::make_iterator_range(m,m.size()-n,0)
|boost::Adapters::映射_值
//|boost::adapters::reversed//按相反顺序输入注释以进行复制
));
}
首先,我们想写什么来成为习惯用语?我建议:
std::vector<Mytype> v;
v.reserve(n);
std::transform(
limited(n, m.rbegin()),
limited_end(m.rend()),
std::back_inserter(v),
values_from(m)
);
实施limited
有点痛苦。它是一个返回迭代器的模板函数。它返回的迭代器类型是一个模板,它包装了另一个迭代器类型,并将所有内容转发给它,除了它跟踪n
,并且在它被提升n
次时,它就像一个结束迭代器一样limited_end
返回一个相同类型的end迭代器,因此如果基础迭代器相等,或者如果其中一个迭代器是使用limited_end
创建的,而另一个迭代器已运行n
到零,则它会比较相等
我手头没有这方面的代码,但这基本上是如何获得所有标准算法的等价物,而不仅仅是copy\n
。在本例中,我们需要转换,但没有
transform
的一种替代方法是使用copy\n
和boost::transform\u迭代器
环绕m.rbegin()
。我在这里也不会这样做,因为我总是要检查文档以使用transform\u迭代器,但是std::copy
和std::transform
是有原因的……)@jalf:不过,我很确定这并不是为了强迫你写几十行代码,把所有可能的东西都转换成转换。你从哪里得到“几十行代码”?为什么使用transform
的答案会更长?但是在向量中,OP只需要地图的值部分。这一点很好!现在我可能不得不把它作为读者的练习,过一会儿再回来讨论……地图迭代器上也没有+
操作符。换句话说,这根本不起作用。:)如果映射包含少于n
个元素,则存在未定义的行为。我声明了大小,但结果是完全失败的。将在以后修复,除非当时接受了更好的方法。这是一个良好的开端。(我特别喜欢使用lambda。)但是如果映射不包含n
元素,会发生什么呢?你也需要检查一下。map::value\u type
是std::pair
,顺便说一句。@JamesKanze:true。我试图省略所有不重要的东西,比如错误检查,因为这会把示例代码弄得一团糟,我更喜欢让它尽可能简短。但很明显,要真正使用代码,您必须处理可能出现的错误情况。@jalf-Hmm。我不确定是否同意“不重要的东西,如错误检查”的说法。更重要的是,我不确定省略它是否是一个好主意,因为许多程序员确实在实际代码中忘记了它。最好树立一个好的榜样(或者至少提到它被省略了)。在回答被问的问题时不重要。是的,这在实际编写工作代码时是很重要的,但是还有许多其他我很方便地省略的东西。OP询问如何从地图的最后N个元素创建向量(
std::vector<Mytype> v;
v.reserve(n);
std::transform(
limited(n, m.rbegin()),
limited_end(m.rend()),
std::back_inserter(v),
values_from(m)
);
template <typename Map>
Second<Map::value_type> values_from(const Map &) {
return Second<Map::value_type>();
}