C++ valarray获取(访问)对象方法详解

C++ valarray获取(访问)对象方法详解,第1张

概述valarray 对象以序列的方式保存其中的元素。像之前说的那样,通过使用下标运算符来使用索引可以得到任何元素的引用,并能够获取或设置值。下面是一些示例: std::valarrayint data {1,2, valarray 对象以序列的方式保存其中的元素。像之前说的那样,通过使用下标运算符来使用索引可以得到任何元素的引用,并能够获取或设置值。下面是一些示例:
std::valarray<int> data {1,2,3,4,5,6,7,8,9};data[1] = data[2] + data[3]; // Data[1] is   7data[3] *= 2; // Data[3] is   8data[4] = ++data[5] - data[2];// data[4] is 4,data[5] is 7
这就像访问一般数组的元素一样。但是,valarray 对象的下标运算符有更多用处。可以用有下标运算符的辅助类的实例来代替索引。这使我们能够指定和访问元素的子集。辅助类定义的元素选择机制使它们可以用于元素,只要这些元素所在的数组是二维或更多维数的数组。理解这是如何工作的很重要,因为这是 valarray 超越序列容器的主要优势。

还有很多细节,因此让我们先看看大致的流程。我们首先会探讨元素选择机制一般是如何工作的,然后如何从二维数组中选择特定的行或列。会解释如何将辅助类用于 valarray 对象以不同方式选择的元素子集上,以及如何表示子集。在说明生成子集的各种可能方式之后,会讨论能对它们做些什么。在这之后,会展示如何将这些技术运用到应用的场景中。
创建切片std::slice 类定义在 valarray 头文件中。由传给 valarray 对象的下标运算符的 slice 对象定义的 slice 就像索引。可以用 slice 对象作为 valarray 对象的下标来选择两个或更多个元素。被选择的元素不需要是数组中的连续元素。slice 选择的数组元素可以作为引用,因此可以访问或改变这些元素的值。

从根本上说,slice 对象为从 valarray 选择的元素封装了一系列索引。可以将 3 个 size_t 类型的值传给 slice 构造函数来定义 slice 对象:
valarray 对象中的 start index (起始索引)指定了子集的第一个元素;size 是子集中的元素个数;strIDe (步进)是为从子集中得到下一个元素的 valarray 索引的增量;
构造函数的参数釆用描述的顺序,因此可以按如下方式定义 slice 对象:
slice my_slice {3,2}; // start index = 3,size = 4,strIDe = 2
这个对象指定了从索引 3 开始的 4 个元素,后续索引的增量为 2。也有构造函数,因此可以复制进行 slice 对象。默认的构造函数会将 start index、size 和 strIDe 全部设为 0,它的唯一目的是进行切片对象数组的创建。

可以调用 slice 对象的成员函数 start() 来得到它的 start index。slice 对象也有成员函数 size() 和 strIDe(),它们各自返回 size 和 strIDe。返回的 3 个值都是 size_t 类型。

通常,在使用 slice{start,size,strIDe} 对象作为 valarray 对象的下标时,可以选择索引值位置的元素:

start,start + strIDe,start + 2*strIDe,...start + (size - 1)*strIDe

图 1 用一个值从 1 到 15 的 valarray 对象进行了展示。
@H_419_29@

图 1 slice 对象选择的 valarray 中的元素子集
图 1 中以 slice 对象为 data 的下标运算符的参数会选择索引位置在 3、5、7、9 的元素,它们是数组中的第 4 个、第 6 个、第 8 个和第 10 个元素。slice 构造函数的第一个参数是第一个元素的索引,第二个参数是索引值的个数,第三个参数是索引值从一个到另一个的增量。用 slice 对象作为 valairay<T> 对象的索引的结果是得到另一个对象,它是一个 slice_array<T> 类型的对象,封装了 slice 在 valarray<T> 中选择的元素的引用。在解释更多关于如何使用分片之后,会回来说明能够用 slice_array 对象做些什么。
选择行假设图 1 中 data 对象的值表示的是有 3 行 5 个元素的二维数组——按行的顺序,图 2 说明了如何用 slice 对象选择第二行。
@H_419_29@

图 2 选择二维数组的单行
start index 是第二行的第一个元素的索引,值为 15。strIDe 是 1,每一行内的元素都是连续保存的。size 是 5,因为每行有 5 个元素。调用表示一行的 slice 对象的成员函数会返回这一行的第一个元素,在我们使用多行时,这是很有用的。当然,a_slice 定义的 valarray 对象的第 n 个元素(索引从 0 开始)的索引是 a_slice.start()+n。
选择列假设想从二维数组中选择一列。数组中列的元素不是连续的。图 3 说明了如何定义一个 slice 对象来选择图 2 中同一个数组的第三列。
@H_419_29@

图 3 从二维数组中选择单列
一如往常,start value 是子序列的第一个元素的索引。列中一个元素到下一个元素的增量是 5,每一列有 3 个元素,因此 size 是 3。
使用切片在用 slice 对象作为下标时,slice_array<T> 对象是从 valarray<T> 对象选择的元素子集的代理。这个模板定义了有限个数的成员函数。slice_array 可用的唯一的 public 构造函数是拷贝构造函数,所以唯一的可能是用来生成对象,远不止用 slice 对象作为下标,还可以用来生成 slice_array 对象的副本。例如:
valarray<int> data(15);std::iota(std::begin(data),std::end(data),1);size_t start {2},size {3},strIDe {5};auto d_slice = data[slice {start,size,strIDe}];//References data[2],data[7],data[12]slice_array<int> copy_slice {d_slice}; // Duplicate of d_slice
这里没有默认的构造函数,因此无法生成 slice_array 对象的数组。可以应用到 slice_array 对象的唯一 *** 作是赋值和复合赋值。赋值运算符会将 slice_array 对象引用的全部元素设为给定值。也能够用它将被引用的元素设为另一个 valarray 对应元素的值,只要这个 valarray 与 slice_array 对象关联的 valarray 有相同的元素个数和类型。例如:
valarray<int> data {1,9,10,11,12,13,14,15};valarray<int> more {2,6};data[slice{0,1}] = 99; // Set elements in 1st row to 99data [slice{10,1} ] = more; // Set elements in last row to values from morestd::cout << "data:\n";print(data,4);
可以看到,能够很容易用 data[slice{0,5,1}] 这种表达式在赋值运算的左边生成 slice_airay。这里调用了 slice_array 的成员函数 operator=()。右 *** 作数可以是一个单值元素,或是一个包含相同类型元素的 valarray,或是另一个同类型的 slice_array。将单值元素赋给 slice_array 会将 valarray 中的元素设置为它所引用的值。当右 *** 作数是 valarray 或 slice_array 时,必须保证它至少包含和左 *** 作数一样多的元素;如果元素没有那么多,得到的结果将不是我们想要的。执行上面的代码,输出是:

data:
99  99  99  99  99
6   7   8   9   10
2  2   3   3   3

可以看到 data 的第一行和第三行已经被改变了。

下面的任何一个复合赋值运算符 (op=) 都可以用于 slice_array 对象:
算术运算符+=、-=、*=、/-、%=位 *** 作运算符&=、|=、^=移位运算符>>=、<<=
在每种情况下,左 *** 作数都必须是一个 slice_array 对象,右 *** 作数都必须是一个包含和 slice_array 同类型元素的 valarray 对象。op= 运算符会将 op 运用到 slice_array 的每一个元素引用和作为右 *** 作数的 valarray 的相应元素之间。注意不支持单值右 *** 作数;总是需要用一个 valarray 对象作为右 *** 作数,即使右边的所有对应元素的值都相同。

右 *** 作数 valarray —般会包含和左 *** 作相同个数的元素,但不是绝对必要的。它包含的元素不能比另一个 *** 作数少,但可以多。如果 slice_array 是有 n 个元素的左 *** 作数,运算会使用右 *** 作数的前 n 个元素。下面是一个用 += 来修改 valarray 对象的分片的示例:
valarray<int> data {1,5A 6,15};auto d_slice = data [slice {2,5} ] ; // References data [2],data [7],data [12]d_slice += valarray<int>{10,20,30}; // Combines the slice with the new valarraystd::cout << "data: \n";print(data,4);
对于 data 中被 d_slice 引用的元素,有更多的对象会被加到相应索引位置的元素值上。输出如下:

data:
1   2   13  4  5
6   7   28  9   10
11  12  43  14  15

在这个运算之后,slice 所选的 data 数组中列元素的值是从 3+10、8+20 和 13+30 得到的。在分片中和元素相乘也很简单:
valarray<int> factors {22,17,10};data[slice{0,5}] *= factors; // Values of the 1st column: 22 102 110
slice 对象会选择 data 中的第一列,这一列的每一个元素都会和 factor 对象中的相应元素相乘。如果只是想用分片乘以一个给定的值,可以只生成一个适当的 valarray 对象:
valarray<int> data {1,15};slice row3 {10,1};data[row3] *= valarray<int>(3,row3.size ()); // Multiply 3rd row of data by 3
data 中的后 5 个元素会乘以 3。在最后一条语句中,通过调用 slice 对象的成员函数 size() 设置了右 *** 作数 valarmy 中的元素个数。这保证了元素个数和 data 中被选择的元素个数是相同的。

假设想将 data 中的一列元素加到另一列上,我们不能将一个 slice_array 加到另一个 slice_array 上,但仍然可以做我们想做的事。一种方式是使用一个接受 slice_array 为参数的 valarray 构造函数。通过这个构造函数,slice_array 对象引用的值会被用来初始化被生成的 valarray 对象中的元素。然后可以用这个对象作为 slice_array 的复合赋值中的右 *** 作数。下面展示了如何将 data 中的第 5 列元素加到第 2 和第 4 列上:
valarray<int> data {1,15};valarray<int> col5 {data[slice{4,5}]}; // Same as 5th column in datadata[slice{1,5}] += col5;  // Add to 2nd columndata[slice{3,5}] += col5;   // Add to 4th columnprint(data,4);
以 slice 对象作为索引的 data 被作为参数对象传给 valarray 的构造函数,从而可以生成一个 slice_array 对象,它可以用来生成对象 col5。valarray 构造函数并不是被显式定义的,因此它可以将 slice_array 类型隐式转换为 valarray 类型。可以按如下方式定义 col5 对象:
valarray<int> col5 = data [slice{ 4,5} ] ; // Convert slice_array to valarray
这里调用了 col5 对象的成员函数 operator=(),它需要一个 valarray 对象作为右 *** 作数。编译器会为接受一个 slice_array 对象作为参数的 valarray 构造函数插入一个调用来将 slice_array 转换为 valarray。注意这和下面的语句并不相同:
auto col = data[slice{4,5}]; // col will be type slice_array
这里并没有发生转换。只是将 col 定义为以 slice 对象为索引从 data 中得到的 slice_array 对象。

调用 print() 的上一段代码产生的输出为:

1 7 3 9 5
6 17 8 19 10
11 27 13 29 15

当然,也能用一个简单的老式循环来做同样的事:
size_t row_len {5},n_rows {3}; // Row length,number of rowsfor(size_t i {}; i < n_rows*row_len; i += row_len){    data[i+1] += data[i+4]; // Increment 2nd column    data[i+3] += data[i+4]; // Increment 4th column}
循环索引 i 选择 data 中的第一列元素的索引值为步进。在循环体中使用 i+n 形式的表达式作为 data 的下标来从第 n 列选择元素。 总结

以上是内存溢出为你收集整理的C++ valarray获取(访问)对象方法详解全部内容,希望文章能够帮你解决C++ valarray获取(访问)对象方法详解所遇到的程序开发问题。

如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/langs/1231458.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-06-06
下一篇 2022-06-06

发表评论

登录后才能评论

评论列表(0条)

保存