哪个 STL 容器具有切片成两个或多个容器的设施
Which STL container has facilities for slicing into two or more containers?
假设我有一个向量/列出填充了 2300 个值
的任何整数我希望能够轻松地将其切成 4 个向量/列表(不一定大小相等)。
例如
vec1 ( elements 0 - 500 )
vec2 ( elements 501 - 999)
vec3 ( elements 1001 - 1499)
等。
一种常见的方法是使用一个容器,并在其上定义单独的迭代器范围。
std::vector<int> vec(2300);
it0 = vec.begin();
it1 = vec.begin() + 500;
it2 = vec.begin() + 1000;
it3 = vec.begin() + 1500;
it4 = vec.begin() + 2000;
it5 = vec.end();
现在,第一个范围仅由迭代器it0
和it1
定义。第二个由it1
和it2
,依此类推。
因此,如果要将函数应用于第三个范围中的每个元素,只需执行以下操作:
std::for_each(it2, it3, somefunc);
实际上,将元素复制到单独的容器中可能是不必要的,并且会带来性能成本。
std::list
将是最佳选择,因为您只需通过连接指针来构建列表。但是,找到切片的确切位置将是问题所在,因为您必须到达列表迭代器中的该点才能进行切割。
编辑:
根据评论(感谢您的见解),也许使用 std::vector<int>
和迭代器是个好主意。但是,使用普通迭代器,您会丢失向量的长度,因此我建议使用例如boost::range_iterator
:
std::vector<int> vec(2300);
it0 = vec.begin();
it1 = vec.begin() + 500;
it2 = vec.begin() + 1000;
it3 = vec.begin() + 1500;
it4 = vec.begin() + 2000;
it5 = vec.end;
typedef boost::iterator_range< std::vector<int>::iterator > my_slice_t;
my_slice_t slice1 = boost::make_iterator_range(it0, it1);
...
然后,您可以将 slice1 用作每个迭代的普通基础std::vector<int>
:
std::for_each(slice1.begin(), slice1.end(), /* stuff */);
请参阅此处记录的第四个std::vector<>
构造函数。
// given std::vector<T> vec with 2300 elements
std::vector<T> vec1(vec.begin(), vec.begin() + 500);
std::vector<T> vec2(vec.begin() + 500, vec.begin() + 1000);
std::vector<T> vec3(vec.begin() + 1000, vec.begin() + 1500);
std::vector<T> vec4(vec.begin() + 1500, vec.begin() + 2000);
std::vector<T> vec5(vec.begin() + 2000, vec.end());
使用向量容器是可行的
#include <vector>
#include <iostream>
using namespace std ;
int main()
{
vector<int> ints ;
vector<int> ints_sliced;
int i ;
// populate
for( i = 0 ; i < 100 ; i++ )
ints.push_back(i) ;
// slice from 10-19
ints_sliced.insert(ints_sliced.begin(), ints.begin()+10, ints.begin()+20) ;
// inspect
vector<int>::iterator it ;
for( it = ints_sliced.begin() ; it != ints_sliced.end() ; it++ )
cout << *it << endl ;
}
哦,如果你碰巧使用 g++ 和 GNU stdlibc++,你可以大致使用
g++ -march=native -O3 -ftree-vectorize ...
如果你也加入GNU OpenMP支持(libgomp),你可以从标准算法的自动并行化中受益(评估,分析!)。
g++ -D_GLIBCXX_PARALLEL -fopenmp -march=native -O3 .... -lgomp
YMMV - 我想把它扔在那里,因为例如并行for_each似乎接近你想要的(但是,自动魔术和自适应容器大小、迭代器类型和处理器数量)
除了@jalf的正确观察之外,实际上将子向量复制到新的向量中可能是浪费时间和空间,让我指出 valarray。
简介:瓦拉阵列
Valarray 可能更复杂,但尤其是在面对并行处理时,可能会导致更好的方法来为不同的线程进行子向量工作。 要寻找的东西:
- 算法预科学(如果某个模式中的位置具有某种属性(例如已知为零),您可以将其交给优化的工人以获取这些值)
- 子向量对齐(这种一致性可以决定 SIMD、SSE4 优化版本的可用性;请查看 gcc -ftree-vectorizer 了解更多背景信息)
现在 valarrays 有很多"晦涩难懂"的操作和技巧(gslices;基本上是重新矢量化的数组维度以解决原始数组),我不会在这里讨论,但足以说,如果你想在(主要是)浮点[1]的连续数组的子集之间进行数字运算,阅读这些是值得的。
强制性(脑死亡)预告片
// mask_array example
#include <iostream>
#include <valarray>
using namespace std;
int main ()
{
valarray<int> myarray (10);
for (int i=0; i<10; ++i) myarray[i]=i; // 0 1 2 3 4 5 6 7 8 9
valarray<bool> mymask (10);
for (int i=0; i<10; ++i)
mymask[i]= ((i%2)==1); // f t f t f t f t f t
myarray[mymask] *= valarray<int>(10,5); // 0 10 2 30 4 50 6 70 8 90
myarray[!mymask] = 0; // 0 10 0 30 0 50 0 70 0 90
cout << "myarray:n";
for (size_t i=0; i<myarray.size(); ++i)
cout << myarray[i] << ' ';
cout << endl;
return 0;
}
这是从上面的链接逐字复制的,您将需要适应您的特定需求。你可能有一个很好的理由让你的最终目标有点模糊,所以我很乐意把剩下的工作留给你!
总结
然而,如果你真的想一路走下去,你应该开始看看大枪(Blitz++等)。
[1] 这些历来是矢量化 CPU 指令集的重点。但是,als @jalf 注释、SSE2 及更高版本也包括 SIMD 整数指令
- 如何在C++中从两个单独的for循环中添加两个数组
- 为什么两个不同的未命名名称空间可以共存于一个cpp文件中
- 当在同一名称空间中有两个具有相同签名的函数时,会发生什么
- 如何返回一个类的两个对象相加的结果
- 如何在C++中将一个无符号的 int 转换为两个无符号的短裤?
- 如何将两个不同矢量的同一位置的两个元素组合在一起
- 两个字符串在 c++ 中不相等
- 在两个类中共享相同的函数调用,并在不需要时避免空实例化
- 两个文件使用彼此的功能-如何解决
- 为什么Mat类的两个对象可以在不重载运算符+的情况下添加
- 如何确保在使用基于布尔值的两个方法之一调用方法时避免分支预测错误
- 停止cmake target_link_libraries将插件中静态库的两个对象文件链接到静态库本身
- 将fold表达式与std::一起用于两个元组
- 如何在C++中比较两个char数组
- 给定两个偶数,求出它们之间所有偶数的平方和
- 比较两个大小不等的映射c++
- C++需要帮助从用户那里获得一个整数,并确保它在另外两个整数之间
- 如何在for循环中包含两个索引值的测试条件
- 在声明中合并两个常量"std::set"(不是在运行时)
- 哪个 STL 容器具有切片成两个或多个容器的设施