Search code examples
c++stlstdvectorunordered-set

Store selected fields from an unordered set on struct to a vector


I have an unordered_set that stores the following struct

struct match_t{
  size_t score;
  size_t ci;  
};

typedef std::unordered_set<match_t> uniq_t;

Now I want to store the elements of uniq_t myset; to a vector, but in doing so, I want to copy just the score and not the entire struct. I have seen solutions for assigning the elements using assign or back_inserter. I was wondering how to select just the required fields from the struct. I don't see any parameter in assign or back_inserter for this purpose.

Should I try overriding push_back method for the vector or are there other methods for doing this?

EDIT 1 Do I get any performance improvements by using any of these methods instead of looping over the set and assigning the required values?


Solution

  • There is nothing wrong a simple for loop:

    std::unordered_set<match_t> myset;
    std::vector<std::size_t> myvec;
    
    myvec.reserve(myset.size()); // allocate memory only once
    
    for (const auto& entry : myset)
        myvec.push_back(entry.score);
    

    Alternatively, you could use std::transform with a custom lambda:

    #include <algorithm>
    
    std::tranform(myset.cbegin(), myset.cend(), std::back_inserter(myvec),
        [](const auto& entry){ return entry.score; });
    

    Another way is to use a range library, e.g. with range-v3

    #include <range/v3/view/transform.hpp>
    
    std::vector<std::size_t> myvec = myset | ranges::view::transform(&match_t::score);
    

    Performance-wise, you can't do anything about the linear pass over all match_t objects. The important tweak instead is to minimize the number of allocations. As the size of the resulting std::vector is known a priori, a call to std::vector::reserve as shown above makes sure that no unnecessary allocation occur.