【问题标题】:C++, std::transform replace items by indicesC++,std::transform 用索引替换项目
【发布时间】:2012-02-20 22:25:26
【问题描述】:

int v1和v2有2个未排序的向量,其中v1包含v2的一个子集

v1: 8 12 4 17
v2: 6 4 14 17 9 0 5 12 8 

有什么办法,如何用 v2 中的位置索引替换 v1 的项目?

v1: 8 7 1 3

这样的算法用2个循环写是没问题的……

但是有没有使用 std::transform 的解决方案?

【问题讨论】:

    标签: c++ vector transform replace indices


    【解决方案1】:

    std::transform 与调用std::find 的函数对象结合起来:

    #include <vector>
    #include <algorithm>
    #include <iostream>
    #include <iterator>
    
    struct find_functor
    {
      std::vector<int> &haystack;
    
      find_functor(std::vector<int> &haystack)
        : haystack(haystack)
      {}
    
      int operator()(int needle)
      {
        return std::find(haystack.begin(), haystack.end(), needle) - haystack.begin();
      }
    };
    
    int main()
    {
      std::vector<int> v1 = {8, 12,  4, 17};
      std::vector<int> v2 = {6,  4, 14, 17, 9, 0, 5, 12, 8};
    
      // in c++11:
      std::transform(v1.begin(), v1.end(), v1.begin(), [&v2](int x){
        return std::find(v2.begin(), v2.end(), x) - v2.begin();
      });
    
      // in c++03:
      std::transform(v1.begin(), v1.end(), v1.begin(), find_functor(v2));
    
      std::cout << "v1: ";
      std::copy(v1.begin(), v1.end(), std::ostream_iterator<int>(std::cout, " "));
      std::cout << std::endl;
    
      return 0;
    }
    

    输出:

    $ g++ -std=c++0x test.cpp
    $ ./a.out 
    v1: 8 7 1 3 
    

    【讨论】:

    • @Jared Hoberock:谢谢,我可以要求没有 lambda 表达式的解决方案吗?我对他们没有任何经验......
    • @justik:这只是一种奇特的 C++11 创建函数对象的方式。所以只需创建一个具有该函数的类型作为其operator()。一个对象,它将对 std::Vector&lt;int&gt; 的引用作为构造函数参数和类成员。
    • @justik:我已经更新了示例以提供省略 lambda 函数的 c++03 解决方案。
    【解决方案2】:

    std::transform 采用一元函数类对象。因此,您可以创建一个高效执行此操作的函子类,使用第二个向量构造它,然后将该函子应用于第一个向量。

    template <typename T>
    class IndexSeeker{
        private:
            map<T, int> indexes;
        public:
            IndexSeeker(vector<T> source){
                for(int k = 0; k < t.size(); ++k){
                    indexes[source[k]] = k;
                }
            }
    
            int operator()(const T& locateme){
                if(indexes.find(T) != indexes.end()){
                    return indexes[T];
                }
                return -1;
            }
    }
    

    通过将整个第二个列表缓存到地图中,查找索引是有效的,而不需要线性搜索。这要求类型 T 是可排序的(因此是可映射的)。如果 T 不可排序,则需要一种需要蛮力搜索的效率较低的方法。

    【讨论】:

      【解决方案3】:

      您可以在转换中使用std::find()

      std::transform(v1.begin(), v1.end(), v1.begin(), [&](int v)->int {
          return std::find(v2.begin(), v2.end(), v) - v2.begin());
      });
      

      【讨论】:

        猜你喜欢
        • 2016-02-04
        • 2020-01-23
        • 1970-01-01
        • 1970-01-01
        • 2016-12-24
        • 1970-01-01
        • 2013-05-30
        • 2021-07-23
        • 2015-07-20
        相关资源
        最近更新 更多