从 C++ 中的单个向量创建成对的向量
Create a vector of pairs from a single vector in C++
我有一个大小均匀的向量,我想将其转换成对向量,其中每对向量始终包含两个元素。我知道我可以使用简单的循环来做到这一点,但我想知道是否有一个很好的标准库工具可以做到这一点?可以假设原始向量总是包含偶数个元素。
示例:
vector<int> origin {1, 2, 3, 4, 5, 6, 7, 8};
vector<pair<int, int>> goal { {1, 2}, {3, 4}, {5, 6}, {7, 8} };
直观但不幸的是无效的方法
有一种quick-and-dirty方法,它会kinda-hopefully-maybe做你要求的,甚至根本不会复制数据...但缺点是你不能确定它会起作用。它依赖于 undefined behavior,因此不推荐使用。我描述它是因为我相信这是人们凭直觉想象的,我们可以做到的。
所以,它是关于使用 和矢量数据的 re-interpretation:
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 };
在 GodBolt
上查看
注意事项:
reinterpret_cast
是“脏的”。它正式导致未定义的行为,它在实践中的作用取决于编译器和平台。如果您也忘记了 std::pair
,而是使用二维 mdspan,则可以避免这种情况。当然,mdspan
不在标准库中。
- 这是 C++20。在 C++20 之前,您仍然可以使用 span,但它们不在标准库中。
- 具体来说,如果您在不允许未对齐访问的平台上,坚持在
goal.data()
处存在 twice-the-size-of-int 值可能是个问题。
使用 Range-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;
}
请注意,如果您只需要在 result
上循环,则可以省略 | to_vector
,因为您仍然可以执行 result.begin()
和 result.end()
,例如。
如果您不需要内部容器真正成为 std::pair
s,但您只是喜欢调用 result.front().front()
而不是 result.front().first
,那么您可以离开还有 transform
,对 auto result = origin | chunk(2);
感到满意。
你没有提到为什么你只想要一个标准的解决方案。但是请考虑 <ranges>
是 C++20 中的 标准。不幸的是,该功能不如 pre-C++20 Range-v3 库强大。但它会在某个时候(C++23?),我认为毫无疑问。
我有一个函数可以处理向量中的偶数和奇数元素。它的作用是使用另一个参数在对的末尾添加一个数字。 我认为从 C++ 20
开始没有任何标准 tool/library 可以这样做,Range-v3
库将在 C++ 23
尚未发布。
这里是try it onlinelink.
#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;
}
如@康桐薇所述,如果您还愿意使用 ranges-v3 库,则可以使用 chunk()
视图:
std::vector origin = {1, 2, 3, 4, 5, 6, 7, 8};
auto goal = v | ranges::views::chunk(2) | ranges::to<std::vector>;
看到它在 GodBolt.
上运行
与我的 不同,这将是完全有效的 language-wise。
注意事项:
- 这将复制您的数据!
- 可能会在您的目标代码中引入 一堆 内容(错误字符串、异常处理程序等)。
- 范围库显着增加了编译时间(尽管启用 C++20 后编译时间可能会减少?)
- 不基于标准库 - 但显然
chunk()
和 to()
将在 C++23 中,因此最多进行轻微的语法调整(例如添加 std::
),这将是有效的 C++23,仅包含标准库。
goal
的元素不是 std::pair
,而是范围。您将需要获取第一个和第二个,或第一个和最后一个元素来组成实际的一对。
我有一个大小均匀的向量,我想将其转换成对向量,其中每对向量始终包含两个元素。我知道我可以使用简单的循环来做到这一点,但我想知道是否有一个很好的标准库工具可以做到这一点?可以假设原始向量总是包含偶数个元素。
示例:
vector<int> origin {1, 2, 3, 4, 5, 6, 7, 8};
vector<pair<int, int>> goal { {1, 2}, {3, 4}, {5, 6}, {7, 8} };
直观但不幸的是无效的方法
有一种quick-and-dirty方法,它会kinda-hopefully-maybe做你要求的,甚至根本不会复制数据...但缺点是你不能确定它会起作用。它依赖于 undefined behavior,因此不推荐使用。我描述它是因为我相信这是人们凭直觉想象的,我们可以做到的。
所以,它是关于使用
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 };
在 GodBolt
上查看注意事项:
reinterpret_cast
是“脏的”。它正式导致未定义的行为,它在实践中的作用取决于编译器和平台。如果您也忘记了std::pair
,而是使用二维 mdspan,则可以避免这种情况。当然,mdspan
不在标准库中。- 这是 C++20。在 C++20 之前,您仍然可以使用 span,但它们不在标准库中。
- 具体来说,如果您在不允许未对齐访问的平台上,坚持在
goal.data()
处存在 twice-the-size-of-int 值可能是个问题。
使用 Range-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;
}
请注意,如果您只需要在 result
上循环,则可以省略 | to_vector
,因为您仍然可以执行 result.begin()
和 result.end()
,例如。
如果您不需要内部容器真正成为 std::pair
s,但您只是喜欢调用 result.front().front()
而不是 result.front().first
,那么您可以离开还有 transform
,对 auto result = origin | chunk(2);
感到满意。
你没有提到为什么你只想要一个标准的解决方案。但是请考虑 <ranges>
是 C++20 中的 标准。不幸的是,该功能不如 pre-C++20 Range-v3 库强大。但它会在某个时候(C++23?),我认为毫无疑问。
我有一个函数可以处理向量中的偶数和奇数元素。它的作用是使用另一个参数在对的末尾添加一个数字。 我认为从 C++ 20
开始没有任何标准 tool/library 可以这样做,Range-v3
库将在 C++ 23
尚未发布。
这里是try it onlinelink.
#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;
}
如@康桐薇所述,如果您还愿意使用 ranges-v3 库,则可以使用 chunk()
视图:
std::vector origin = {1, 2, 3, 4, 5, 6, 7, 8};
auto goal = v | ranges::views::chunk(2) | ranges::to<std::vector>;
看到它在 GodBolt.
上运行与我的
注意事项:
- 这将复制您的数据!
- 可能会在您的目标代码中引入 一堆 内容(错误字符串、异常处理程序等)。
- 范围库显着增加了编译时间(尽管启用 C++20 后编译时间可能会减少?)
- 不基于标准库 - 但显然
chunk()
和to()
将在 C++23 中,因此最多进行轻微的语法调整(例如添加std::
),这将是有效的 C++23,仅包含标准库。 goal
的元素不是std::pair
,而是范围。您将需要获取第一个和第二个,或第一个和最后一个元素来组成实际的一对。