惯用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(n
std::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>();
}