Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Storing from std::vector to std::set where vector contains a structure but std::set contains only one element from the struct

Tags:

c++

set

vector

How do I copy all elements of a vector which is a struct of elements, to a set.

    struct info
    {
      std::string code;
      std::string curDate;
      int         iVar;

    };

    std::vector<info> infVect; // Load data into the vector from the database

    std::set<std::string> uniqueCodes;


  for ( int i = 0; i < infVect.size() ; ++i)
      uniqueCodes.insert(infVect[i].code);

Is there a faster way to store the elements from vector to set without iterating each element in the loop?

Note:

std::set<std::string> uniqueCodes(infVect.begin(), infVect.end() ), would work if infVect had only code. But infVect is a vector of objects.

like image 892
nsivakr Avatar asked Dec 08 '25 23:12

nsivakr


2 Answers

Your code is absolutely fine. A for loop is the simplest way to express what you mean in this situation. A C++11 range-based for is even simpler:

for (const auto& i : infVect)
  uniqueCodes.insert(i.code);

If you want an alternative for the sake of having one, here’s how to do it by only gluing together STL features.

Run it through std::transform to extract the member and insert it into the set. The mem_fn helper turns a member function or member variable into a functor.

std::transform(
  infVect.begin(),
  infVect.end(),
  std::inserter(uniqueCodes, uniqueCodes.end()),
  std::mem_fn(&info::code)
);

If code were private, you’d need a getter to give to mem_fn.

const std::string& getCode() const { return code; }

You need the following headers.

#include <algorithm>  // transform
#include <functional> // mem_fn
#include <iterator>   // inserter

If you don’t care about preserving the original vector, you can use std::move_iterator in C++11 to move strings without reallocation, and avoid the <functional> dependency for mem_fn by using a lambda.

using namespace std; // for brevity
transform(
  make_move_iterator(begin(infVect)),
  make_move_iterator(end(infVect)),
  inserter(uniqueCodes, end(uniqueCodes)),
  [](info&& x) { return move(x.code); }
);
like image 113
Jon Purdy Avatar answered Dec 11 '25 13:12

Jon Purdy


You have to visit every node, but you can hide the iteration away in std::transform

struct StringFromInfo { std::string operator()(const Info& info) { return info.code; } };

std::transform(infVect.begin(), infVect.end(), std::back_inserter(uniqueCodes), StringFromInfo());
like image 36
Mark B Avatar answered Dec 11 '25 13:12

Mark B



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!