[英]Create a vector of pairs from a single vector in C++
I have a single even-sized vector that I want to transform into a vector of pairs where each pair contains always two elements.我有一个偶数大小的向量,我想将其转换为成对向量,其中每对总是包含两个元素。 I know that I can do this using simple loops but I was wondering if there is a nice standard-library tool for this?
我知道我可以使用简单的循环来做到这一点,但我想知道是否有一个很好的标准库工具呢? It can be assumed that the original vector always contains an even amount of elements.
可以假设原始向量总是包含偶数个元素。
Example:例子:
vector<int> origin {1, 2, 3, 4, 5, 6, 7, 8};
vector<pair<int, int>> goal { {1, 2}, {3, 4}, {5, 6}, {7, 8} };
Use Range-v3:使用范围-v3:
#include <range/v3/range/conversion.hpp>
#include <range/v3/view/transform.hpp>
#include <range/v3/view/chunk.hpp>
using namespace ranges;
using namespace ranges::views;
int main() {
std::vector<int> origin {1, 2, 3, 4, 5, 6, 7, 8};
std::vector<std::pair<int, int>> goal { {1, 2}, {3, 4}, {5, 6}, {7, 8} };
auto constexpr makePairFromRangeOf2 = [](auto two){
return std::make_pair(two.front(), two.back());
};
auto result = origin | chunk(2)
| transform(makePairFromRangeOf2)
| to_vector;
}
Notice that if you only have to loop on result
, then you only need it to be a range, so you can leave | to_vector
请注意,如果您只需要循环
result
,那么您只需要它是一个范围,所以您可以离开| to_vector
| to_vector
out, because you'll still be able to do result.begin()
and result.end()
, which is what makes result
a range. | to_vector
out,因为您仍然可以执行result.begin()
和result.end()
,这就是使result
成为范围的原因。
If you don't need the inner containers to truly be std::pair
s, but your just happy with calling, say, result.front().front()
instead of result.front().first
, then you can leave also the transform
, and just be happy with auto result = origin | chunk(2);
如果您不需要内部容器真正成为
std::pair
s,但您只是对调用result.front().front()
而不是result.front().first
,那么您可以离开也是transform
,并且对auto result = origin | chunk(2);
感到满意auto result = origin | chunk(2);
. .
You don't mention why you only want a standard solution.你没有提到为什么你只想要一个标准的解决方案。 However consider that
<ranges>
is standard in C++20.但是请考虑
<ranges>
在 C++20 中是标准的。 Unfortunately that feature is not as powerful as pre-C++20 Range-v3 library.不幸的是,该功能不如 C++20 之前的 Range-v3 库强大。 But it will be at some point (C++23?), I think without any doubts.
但它会在某个时候(C++23?),我认为毫无疑问。
As mentioned by @康桓瑋 , if you're willing to also use the ranges-v3 library, you can use a chunk()
view:正如@康桓玮所提到的,如果您愿意也使用 range-v3 库,您可以使用
chunk()
视图:
std::vector origin = {1, 2, 3, 4, 5, 6, 7, 8};
auto goal = v | ranges::views::chunk(2) | ranges::to<std::vector>;
See it working on GodBolt .看到它在GodBolt上工作。
Unlike my other answer , this will be perfectly valid language-wise.与我的其他答案不同,这在语言方面将是完全有效的。
Caveats:注意事项:
chunk()
and to()
will be in C++23, so upto a slight syntax tweak (eg adding std::
), this will be valid C++23 with only standard library includes.chunk()
和to()
将在 C++23 中,因此只需稍作语法调整(例如添加std::
),这将是有效的 C++23,只有标准库包括。goal
are not std::pair
s, bur rather ranges. goal
的元素不是std::pair
s,而是范围。 You will need to get the first and second, or first and last, elements to make an actual pair.I have a function for handling both even and odd number of elements in a vector.我有一个处理向量中偶数和奇数元素的函数。 What it does that it takes another parameter to add a number at the end of pair.
它的作用是需要另一个参数在对的末尾添加一个数字。 I don't think there's any standard tool/library to do so as of
C++ 20
, there is Range-v3
library which will be in C++ 23
which isn't released yet.我认为从 C++ 20 开始没有任何标准工具/库可以这样做,
C++ 20
C++ 23
有Range-v3
库,但尚未发布。
Here is the try it online link.这是在线试用链接。
#include <iostream>
#include <vector>
// time complexity: O(n / 2), where `n` is the length of `my_vec`
std::vector<std::pair<int, int>> vec_to_pair(const std::vector<int> &my_vec, int odd_origin)
{
std::vector<std::pair<int, int>> val;
for (std::size_t i = 0; i < my_vec.size(); i += 2)
{
int sec_val;
if (i < my_vec.size() - 1)
sec_val = my_vec[i + 1];
else if (my_vec.size() % 2 != 0)
sec_val = odd_origin;
else
break;
int data[] = {my_vec[i], sec_val};
val.push_back({data[0], data[1]});
}
return val;
}
void print(const std::vector<std::pair<int, int>> &vec)
{
std::cout << "{ ";
for (auto &&i : vec)
std::cout << "{ " << i.first << ", " << i.second << " } ";
std::cout << " }" << std::endl;
}
int main(void)
{
std::vector<int> vec1 = {1, 2, 3, 4, 5}; // odd
std::vector<int> vec2 = {1, 2, 3, 4, 5, 6}; // even
auto x1 = vec_to_pair(vec1, -1);
auto x2 = vec_to_pair(vec2, 0);
print(x1);
print(x2);
return 0;
}
Simple way of doing this without using the range v3 library:不使用 range v3 库的简单方法:
template <typename T>
std::vector<std::pair<T, T>> windowed(const std::vector<T> &vec) {
const size_t size = vec.size();
if (size % 2 != 0) {
throw std::exception("Vector does not contain an even amount of elements!");
}
std::vector<std::pair<T, T>> result;
for (size_t i = 0; i < size; i = i + 2) {
const T &left = vec.at(i);
const T &right = vec.at(i + 1);
result.emplace_back(left, right);
}
return result;
}
There's a quick-and-dirty approach, which will kinda-hopefully-maybe do what you asked for, and will not even copy the data at all... but the downside is that you can't be certain it will work.有一种快速而肮脏的方法,它可能会按照您的要求进行,甚至根本不会复制数据......但缺点是您不能确定它会起作用。 It relies on undefined behavior , and can thus not be recommended.
它依赖于未定义的行为,因此不推荐。 I'm describing it because I believe it's what one imagines, intuitively, that we might be able to do.
我正在描述它,因为我相信这是人们直观地想象的,我们可能能够做到的事情。
So, it's about using std::span
with re-interpretation of the vector data:所以,它是关于使用
std::span
重新解释矢量数据:
std::vector<int> origin {1, 2, 3, 4, 5, 6, 7, 8};
auto raw_data = reinterpret_cast<std::pair<int, int>*>(origin.data());
std::span<std::pair<int, int>> goal { raw_data, origin.size()/2 };
See this on GodBolt在GodBolt上看到这个
Caveats:注意事项:
reinterpret_cast
is "dirty". reinterpret_cast
是“脏的”。 It officially results in undefined behavior, and what it does in practice depends on the compiler and platform.std::pair
's, and instead use a 2-dimensional mdspan instead.std::pair
,则可以避免这种情况,而是使用二维mdspan 。 Of course, mdspan
's are not in the standard library.mdspan
不在标准库中。goal.data()
.goal.data()
中存在两倍于 int 的值可能是一个问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.