C++ 按索引对向量进行排序

Posted

技术标签:

【中文标题】C++ 按索引对向量进行排序【英文标题】:C++ Sort vector by index 【发布时间】:2021-03-07 17:20:33 【问题描述】:

我需要按索引对 std::vector 进行排序。让我用一个例子来解释一下:

假设我有一个包含 12 个位置(但可以是 18 个)的 std::vector,其中填充了一些值(不必排序):

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()函数并尝试使用,结果真的很糟糕嘿嘿

还发现了这个类似的问题,它按奇数和偶数索引排序,但不知道如何在我的情况下或即使有可能:Sort vector by even and odd index

非常感谢!

注意 0:不,我的向量并不总是排序的。这只是一个例子。我已经更改了值

注 1:我知道这听起来很奇怪......认为它就像 hte vecotr 位置一样:是 是 是 不 不 不 是 是 是 不 不 不 是 是 是...所以“是”的位置会出现相同的顺序,但在“否”位置之前

注意 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

【问题讨论】:

我不明白你到底想做什么。结果向量似乎没有以任何方式排序。您是否想根据索引移动元素? 你检查过这个话题吗? ***.com/questions/1577475/… @AlirezaAbbasi 是的,也找到了,但他们再次使用元素进行排序,而不是索引......我真正需要的是对索引进行排序。但是非常感谢您提供的信息:) @cigien 是的,我知道这有点棘手。索引将被排序为:是的,是的,没有的,没有的,是的,是的,没有的,没有的,所以“是”将比“否”的索引排在前面。也许现在更清楚了? 你的原始向量总是排序的吗?如果是这样,提供的答案解决了问题,但如果原始向量没有排序,它将不起作用。你能澄清一下这个问题吗? 【参考方案1】:

你不想要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

【讨论】:

很好的答案。我完全误解了这个问题。 如果两个部分的大小相同,那么std::swap_ranges 可能是更好的选择。它通常也比std::rotate 快。 非常感谢您的回答,但正如其他人指出的那样,这只有在对向量进行排序时才有效,而在我的情况下,它可能不是。这是一个例子,但令人困惑。对不起。刚刚添加了有关问题的信息 @Blastfurnace - 我不知道std::swap_ranges,所以谢谢。我会更新答案。 @Megasa3 - 通过用新值替换原始值,该算法仍然提供与您想要的相同的输出。排序在哪里发挥作用?【参考方案2】:

使用 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。

【讨论】:

哦,我怕我不能使用外部库,但我什至不知道它似乎太酷了!正如你所说,它非常具有可读性。非常感谢。

以上是关于C++ 按索引对向量进行排序的主要内容,如果未能解决你的问题,请参考以下文章

对向量中具有奇数索引的数字进行排序

对向量元素进行排序[关闭]

R语言使用sort.list函数对向量数据进行排序(默认升序排序)返回排序后的对应索引值

对向量矩阵中的值进行排序,输出对应的索引

我如何按类属性对C++向量数组进行排序[重复]

C++ STL中排序算法的工作