C ++按索引对向量进行排序
C++ Sort vector by index
我需要按索引对 std::vector 进行排序。让我用一个例子来解释它:
假设我有一个 std::vector 的 12 个位置(例如可以是 18 个),其中填充了一些值(不需要排序):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3
我想每 3 个索引对其进行排序。这意味着:前 3 个 [0-2] 留下来,然后我需要 [6-8],然后是其他的。所以它会像这样结束(新索引 3 的值为之前的 idx 6):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 1 2 2 3 2 0 4 5 3
我正在尝试使用 std::sort + lambda 在一行中完成它,但我做不到。还发现了std::partition()这个函数并尝试使用但是结果真的很糟糕嘿嘿
还发现了这个类似的问题,它按奇数和偶数索引排序,但在我的情况下无法弄清楚如何制作它,即使有可能:
非常感谢!
注意0:不,我的向量并不总是排序的。这只是一个例子。我已经更改了值
注意 1:我知道这听起来很奇怪......认为它像 hte vecotr 位置是这样的:是的是的是的不不不不是的是的是的不不不不是的是的......所以 'yes'位置将按相同顺序排列,但在 'no' 个位置
之前
注意 2:如果 lambda 没有办法,那么我想用循环和辅助变量来实现它,但我认为它更难看。
注3:又如:
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3 2 3 0 0 2 1
Sorted Values: 3 0 2 1 2 2 2 3 0 3 2 0 4 5 3 0 2 1
最终向量值排序(根据旧索引):0 1 2 6 7 8 12 13 14 3 4 5 9 10 11 15 16 17
你可以想象那些索引在 2 列中,所以我首先想要左边的,然后是右边的:
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
你不想要 std::sort
,你想要 std::rotate
。
std::vector<int> v = {20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31};
auto b = std::next(std::begin(v), 3); // skip first three elements
auto const re = std::end(v); // keep track of the actual end
auto e = std::next(b, 6); // the end of our current block
while(e < re) {
auto mid = std::next(b, 3);
std::rotate(b, mid, e);
b = e;
std::advance(e, 6);
}
// print the results
std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, " "));
此代码假设每次旋转总是做两组,每组 3 个,但显然您可以使用您想要的任意范围。
输出看起来像你想要的:
20 21 22 26 27 28 23 24 25 29 30 31
更新:@Blastfurnace 指出 std::swap_ranges
也可以。 rotate
调用可以替换为以下行:
std::swap_ranges(b, mid, mid); // passing mid twice on purpose
有了range-v3库,写起来很方便,可读性也很好。假设您的原始向量称为 input
:
namespace rs = ranges;
namespace rv = ranges::views;
// input [3, 0, 2, 3, 2, 0, 1, 2, 2, 4, 5, 3, 2, 3, 0, 0, 2, 1]
auto by_3s = input | rv::chunk(3); // [[3, 0, 2], [3, 2, 0], [1, 2, 2], [4, 5, 3], [2, 3, 0], [0, 2, 1]]
auto result = rv::concat(by_3s | rv::stride(2), // [[3, 0, 2], [1, 2, 2], [2, 3, 0]]
by_3s | rv::drop(1) | rv::stride(2)) // [[3, 2, 0], [4, 5, 3], [0, 2, 1]]
| rv::join
| rs::to<std::vector<int>>; // [3, 0, 2, 1, 2, 2, 2, 3, 0, 3, 2, 0, 4, 5, 3, 0, 2, 1]
这是一个demo。
我需要按索引对 std::vector 进行排序。让我用一个例子来解释它:
假设我有一个 std::vector 的 12 个位置(例如可以是 18 个),其中填充了一些值(不需要排序):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3
我想每 3 个索引对其进行排序。这意味着:前 3 个 [0-2] 留下来,然后我需要 [6-8],然后是其他的。所以它会像这样结束(新索引 3 的值为之前的 idx 6):
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11
Vector Values: 3 0 2 1 2 2 3 2 0 4 5 3
我正在尝试使用 std::sort + lambda 在一行中完成它,但我做不到。还发现了std::partition()这个函数并尝试使用但是结果真的很糟糕嘿嘿
还发现了这个类似的问题,它按奇数和偶数索引排序,但在我的情况下无法弄清楚如何制作它,即使有可能:
非常感谢!
注意0:不,我的向量并不总是排序的。这只是一个例子。我已经更改了值
注意 1:我知道这听起来很奇怪......认为它像 hte vecotr 位置是这样的:是的是的是的不不不不是的是的是的不不不不是的是的......所以 'yes'位置将按相同顺序排列,但在 'no' 个位置
之前注意 2:如果 lambda 没有办法,那么我想用循环和辅助变量来实现它,但我认为它更难看。
注3:又如:
Vector Index: 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Vector Values: 3 0 2 3 2 0 1 2 2 4 5 3 2 3 0 0 2 1
Sorted Values: 3 0 2 1 2 2 2 3 0 3 2 0 4 5 3 0 2 1
最终向量值排序(根据旧索引):0 1 2 6 7 8 12 13 14 3 4 5 9 10 11 15 16 17
你可以想象那些索引在 2 列中,所以我首先想要左边的,然后是右边的:
0 1 2 3 4 5
6 7 8 9 10 11
12 13 14 15 16 17
你不想要 std::sort
,你想要 std::rotate
。
std::vector<int> v = {20, 21, 22, 23, 24, 25,
26, 27, 28, 29, 30, 31};
auto b = std::next(std::begin(v), 3); // skip first three elements
auto const re = std::end(v); // keep track of the actual end
auto e = std::next(b, 6); // the end of our current block
while(e < re) {
auto mid = std::next(b, 3);
std::rotate(b, mid, e);
b = e;
std::advance(e, 6);
}
// print the results
std::copy(std::begin(v), std::end(v), std::ostream_iterator<int>(std::cout, " "));
此代码假设每次旋转总是做两组,每组 3 个,但显然您可以使用您想要的任意范围。
输出看起来像你想要的:
20 21 22 26 27 28 23 24 25 29 30 31
更新:@Blastfurnace 指出 std::swap_ranges
也可以。 rotate
调用可以替换为以下行:
std::swap_ranges(b, mid, mid); // passing mid twice on purpose
有了range-v3库,写起来很方便,可读性也很好。假设您的原始向量称为 input
:
namespace rs = ranges;
namespace rv = ranges::views;
// input [3, 0, 2, 3, 2, 0, 1, 2, 2, 4, 5, 3, 2, 3, 0, 0, 2, 1]
auto by_3s = input | rv::chunk(3); // [[3, 0, 2], [3, 2, 0], [1, 2, 2], [4, 5, 3], [2, 3, 0], [0, 2, 1]]
auto result = rv::concat(by_3s | rv::stride(2), // [[3, 0, 2], [1, 2, 2], [2, 3, 0]]
by_3s | rv::drop(1) | rv::stride(2)) // [[3, 2, 0], [4, 5, 3], [0, 2, 1]]
| rv::join
| rs::to<std::vector<int>>; // [3, 0, 2, 1, 2, 2, 2, 3, 0, 3, 2, 0, 4, 5, 3, 0, 2, 1]
这是一个demo。