Reputation: 3406
I have a simple point structure
struct mypoint
{
int x;
int y;
};
and a vector
of mypoint
s
vector<mypoint> myvector;
If I want to create a vector of int
containing all the coordinates of my points (i.e. x1
, y1
, x2
, y2
, x3
, y3
, ...), I could easily do it in the following way
vector<mypoint>::iterator pt, ptend(myvector.end());
vector<int> newvector;
for(pt=myvector.begin(); pt!=ptend; ++pt)
{
newvector.push_back(pt->x);
newvector.push_back(pt->y);
}
Is there a way to obtain the same result in one (or two) line(s) of code using the C++11?
Upvotes: 1
Views: 3149
Reputation:
As reima already noted, if you only want to reference the existing sequence, it is sufficient to cast myvector.data()
to int*
(assuming sizeof(mypoint) == 2 * sizeof(int)
holds).
However, if you explicitly want a copy of the flattened sequence, you are probably better off creating a small utility function like this:
template <typename T, typename U>
std::vector<T> flatten(std::vector<U> const& other) {
static_assert(std::is_trivially_copyable<U>::value,
"source type must be trivially copyable!");
static_assert(std::is_trivially_copy_constructible<T>::value,
"destination type must be trivially copy constructible!");
static_assert((sizeof(U) / sizeof(T)) * sizeof(T) == sizeof(U),
"sizeof(U) must be a multiple of sizeof(T)!");
return std::vector<T>(reinterpret_cast<T const*>(other.data()),
reinterpret_cast<T const*>(std::next(other.data(), other.size())));
}
template <typename U>
std::vector<typename U::value_type> flatten(std::vector<U> const& other) {
return flatten<typename U::value_type>(other);
}
reducing your code to
auto newvector = flatten<int>(myvector);
or - if you equip your mypoint
struct
with a (STL-conforming) value_type
member type - even to
auto newvector = flatten(myvector);
Note, that this utility function is nothing more than a tweaked constructor using the inherently unsafe reinterpret_cast
to convert mypoint
pointers into int
pointers.
To get rid of the safety caveats that go along with the use of reinterpret_cast
, the flatten
function uses some static_assert
parachutes. So, it's better to hide all this in a seprate function.
Still, it uses a lot of C++11 features like auto
, move construction, static_assert
, type traits, std::next
and vector::data()
which pretty much strips down your call site code to a bare minimum.
Also, this is as efficient as it gets because the range constructor of vector
will only perform the memory allocation and call uninitialized_copy
, which will probably boil down to a call of memcpy
for trivially copyable types.
Upvotes: 1
Reputation: 63775
Since you're using C++11, you can use the new for syntax.
vector<int> newvector;
for( const auto &pt : myvector)
{
newvector.push_back(pt.x);
newvector.push_back(pt.y);
}
Upvotes: 3
Reputation: 2645
You could use a std::pair<>
in which you push the coordinates using std::make_pair
and then push the std::pair<>
into the vector such as:
mypoint a_point;
std::pair<int, int> point = std::make_pair(a_point.x, a_point.y);
vector<std::pair<int, int>> vec.push_back(point).
Perhaps bulky but in two lines it works well and encapsulates a point rather than separating the magnitudes of each point axis and placing them inside a std::vector
.
Upvotes: 1
Reputation: 122391
Here's about 4 lines, using a lambda:
vector<mypoint> points;
vector<int> iv;
points.push_back(mypoint(1,2));
points.push_back(mypoint(3,4));
points.push_back(mypoint(5,6));
for_each(points.cbegin(), points.cend(),
[&iv](const mypoint &pt) {
iv.push_back(pt.x);
iv.push_back(pt.y);
});
Upvotes: 1
Reputation: 6682
steal from the post: C++ std::transform vector of pairs->first to new vector
vector<int> items;
std::transform(pairs.begin(),
pairs.end(),
std::back_inserter(items),
[](const std::pair<int, int>& p) { return p.first; });
Upvotes: 1
Reputation: 3350
std::vector<int> extractIntsFromPoints(const std::vector<mypoint>& pointVector)
{
std::vector<int> retVector;
for (const auto& element : pointVector)
{
retVector.push_back(element.x);
retVector.push_back(element.y);
}
return retVector;
}
Call this function where you need the int vector. I threw in the range-based for loop to make it extra C++11.
Upvotes: 4