【问题标题】:How to get array of data members from array of objects in c++?如何从 C++ 中的对象数组中获取数据成员数组?
【发布时间】:2018-03-21 23:09:59
【问题描述】:

假设我有一个“人”对象数组:

#include <iostream>
class person{
public:
   int age;
   std::string name;
};

是否可以获得与每个人的年龄(或姓名)相同大小的数组?我知道如何使用循环来做到这一点,但我希望有某种“地图”可以让我在一行中得到相同的结果。

【问题讨论】:

  • std::transform 可以使用。不知道那是不是太过分了。
  • 不管你是不是写,都会有一个循环。
  • range-v3: persons | ranges::view::transform(&amp;Person::age).
  • @AndyG 这是写循环的可怕理由。尽管像std::copystd::transform 这样的大多数算法只是简单的循环,但它们极大地提高了可读性。每次您无需手动编写循环就可以侥幸成功。
  • @nwp:我同意。 OP 说他们想避免循环,但我想说这最终是不可避免的。

标签: c++ arrays class mapping


【解决方案1】:

是的,您可以将transform 用于传统数组和标准容器,例如std::vector

使用旧数组

person persons[2] = { { 20, "name1" }, { 21, "name2" } };
for (auto & person : persons)
    cout << person.age << " " << person.name << endl;

decltype(person::age) ages[sizeof(persons)/sizeof(persons[0])];
std::transform(std::begin(persons), std::end(persons), std::begin(ages), [](person & p) -> decltype(person::age) { return p.age; });
for (auto & age : ages)
    cout << age << endl;

使用std::vector

std::vector<person> persons = { { 20, "name1" }, { 21, "name2" } };
for (auto & person : persons)
    cout << person.age << " " << person.name << endl;

std::vector<decltype(person::age)> ages(persons.size());
std::transform(persons.begin(), persons.end(), ages.begin(), [](person & p) -> decltype(person::age) { return p.age; });
for (auto & age : ages)
    cout << age << endl;

这会动态提取原始容器中所有人员的年龄。

【讨论】:

    【解决方案2】:

    为了一般性,我假设数组是指动态大小的数组,那么完整的示例是:

    #include <string>
    struct person {
       int age;
       std::string name;
    };
    
    std::vector<int> getAge(std::vector<person> p) { 
       std::vector<int> result;
       result.reserve(p.size());
       for (auto& e : p) result.push_back(e.age);
       return result;
    }
    

    或者你使用std::transform 那将是

    #include <algorithm>
    int  main() {
        std::vector<person> foo(10);
        std::vector<int>    ages(10);
        std::transform(foo.begin(),foo.end(),ages.begin(),[](person& p){return p.age;});
    }
    

    在任何情况下,都没有从实例数组中获取成员数组的神奇方法。某处一定有一个循环(transform 在隐藏这个循环方面做得很好)。

    【讨论】:

    • @Ron 是的,已修复。直到现在我才发现 OP 要求的是单线。但是,无论是写函数还是使用算法,都可以在一行中完成,并且直接可见,必须有一个循环
    【解决方案3】:

    下面是使用 std::transformstd::back_inserter 和 lambda 的方法:

    #include <iostream>
    #include <algorithm>
    #include <vector>
    #include <iterator>
    
    struct person{
       int age;
       std::string name;
    };
    
    int main()
    {
        std::vector<person> pp = {{16, "Bob"},{32, "Alice"}};
        std::vector<int> ages;
        std::transform(
            pp.begin(), 
            pp.end(), 
            std::back_inserter(ages),
            [](const person& p) -> int { return p.age; });
        for(auto v: ages)
            std::cout << v << " ";
    }
    

    输出:

    16 32 
    

    Live demo

    更新:为避免不必要的重新分配,您可以在调用 std::transform 之前调用 ages.reserve(pp.size())

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2017-10-06
      • 1970-01-01
      • 1970-01-01
      • 2018-01-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多