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