为 C++ 选择 begin() 和 end()
Posted
技术标签:
【中文标题】为 C++ 选择 begin() 和 end()【英文标题】:Selecting the begin() and end() for C++ 【发布时间】:2018-02-13 12:16:15 【问题描述】:我有一个项目要求我按特定列从 .csv 文件读取值并对其进行排序。
我在 C++ 中使用算法库,即#include <algorithm>
该库具有我计划使用的功能sort()
。
它要求我指定开始和结束,例如,对于一个名为 vect 的 2d 向量,它需要 vect.begin()
和 vect.end()
。
我的问题是,是否可以为 sort() 函数指定确切的开始位置和结束位置。这就像从 vect[1][0] 开始并在 vect[9][9] 结束。
感谢您的帮助
【问题讨论】:
你不能std::sort
2D 向量/数组。你希望这样做会有什么结果?
如果vect.begin()
是向量的第一个元素(假设它不为空),那么你认为vect.begin() + 1
是什么?
对列进行间接排序,然后使用索引访问行。在此处查看示例:***.com/questions/48764471/…
@HolyBlackCat 好吧,当我根据一列对值进行排序时,它确实有效,尽管它也将表格的标题移到了底部,这就是我试图避免的
@HolyBlackCat :当然你可以对二维向量进行排序。向量的排序向量的自然定义是结果具有按字典顺序存储的内部向量(因此 [[4, 5, 6], [1, 2, 3], [1, 2, 4]] 将是输出为 [[1, 2, 3], [1, 2, 4], [4, 5, 6]])。当然,实际上,std::vector
没有定义 operator <
。无论如何,OP 都需要一个客户比较函子来选择列。
【参考方案1】:
为了便于讨论,我假设您正在使用std::vector<std::vector<int> >
。同样的讨论也适用于其他类型的二维向量。
如果您想对单个 int
s 进行排序,以便它们在 std::vector<std::vector<int> >
中排序,则无法直接进行。没有可以直接从 std::vector<std::vector<int>>
获得的迭代器,它运行在所有嵌套的 int
s 上。
一种方法可能是在std::vector<int>
中设置一个临时副本(即创建一个扁平的一维向量),对其进行排序,然后将元素复制回来。例如;
std::vector<std:vector<int> > vec;
// populate vec somehow
std::vector<int> elements(0);
// create a single std::vector<int> from the vector<vector<int>> by
// appending the vector<int>s end to end
for (const auto &row : vec)
elements.insert(elements.end(), row.begin(), row.end());
std::sort(elements.begin(), elements.end()); // sort in ascending order
// now copy the sorted elements back
auto start = elements.begin();
for (auto &row : vec) // non-const here since we seek to change the vector<int>s within vec
auto end = start + row.size();
std::copy(start, end, row.begin());
start = end;
最后一个循环中row.size()
和row.begin()
的恶作剧处理了vec
中的vector<int>
大小不同的可能性,因此会发生变化
5,6,7, 1,2, 3,4,8
成为
1,2,3, 4, 5, 6,7,8
而不是其他东西,例如
1,2, 3,4,5, 6, 7, 8; // vector<int>s resized
如果您假设所有内部向量的大小相同,则可以稍微简化一下。
或者,您可以尝试手动滚动 struct
/class
类型,该类型具有随机访问迭代器的所有属性(这是 std::sort()
所要求的)。该结构(或其成员函数/运算符)将需要同时跟踪 std::vector<int>
(在 2D 向量内)和它所引用的该向量内的特定 int
。这将是相当棘手的(例如,如果自定义迭代器引用特定 std::vector<int>
的最后一个元素,递增它必须给出引用下一个 vector<int>
的第一个元素的结果)。 std::vector<std::vector<int> >
根本没有任何内置功能可以直接为您提供这样的迭代器。我将滚动这样一个自定义迭代器作为练习。
【讨论】:
【参考方案2】:鉴于您知道迭代的顺序,您可以指定相对于开始的元素。
vect.begin() // first element
vect.begin() + 2 // third element
因此,如果您只想对第一个元素进行排序,比如说 10 个元素,请使用以下内容:
std::sort(vect.begin(), vect.begin() + 10);
更多here.
正如其他人已经提到的,您不能真正对 2D 矢量进行排序。因此,您要么单独对每个向量进行排序,要么将其展平为 1D 向量并使用索引计算进行 2D 解释。
【讨论】:
那么,考虑到我想防止列标题和行号不被排序,我将如何将 2D 向量展平为 1D 并将其带回 2D。我使用了sort(vect.begin() + 1, vect.end())
,它阻止了对列名进行排序,但仍然对行号进行排序。 谢谢
您不想一直切换数据布局。我想到的是例如如果您有一个 NxN 矩阵,则将其存储在大小为 NxN 的一维向量 v
中。要访问位置 i/j 处的元素,您将使用 v[i * N + j]
。如果这不符合您的想法,可以提供您拥有的矩阵以及您希望如何对其进行排序的示例。【参考方案3】:
-
将排序依据的列加载到
std::vector< std::pair > index;
并设置
作为向量行索引的第一个元素 (0,1,2,...)
第二个元素将是行和列中的值
使用此问题按配对的第二项对其进行排序:How do I sort a vector of pairs based on the second element of the pair?
现在您有了按向量 index
向量中的第一项选择原始二维向量中具有索引的行。【讨论】:
以上是关于为 C++ 选择 begin() 和 end()的主要内容,如果未能解决你的问题,请参考以下文章