数组是IDL中最重要的数据组织形式,IDL中绝大部分函数都支持数组运算。数组的运用范围广,运算方便高效。而要掌握数组的运用,小编认为要掌握IDL中数组运用,最主要的是要弄明白其存储方式。
IDL中数组与数组的运算,多维数组的运算会转换成一维数组来运算。而且IDL中的一些操作函数,像where,unique其处理方式都是将数组先转换为一维数组来警醒进一步的操作与运算。所以只有弄明白IDL的数组的存储方式后,你才能应对自如。
IDL中的数组支持0-8维,下标顺序先列标,后行标,例如数组Array[3, 4]是4行3列。IDL中的数组在内存中是按行存储的,这是因为IDL最初的设计目的是用来处理行扫描卫星数据。
n行m列的二维数组arr[m, n]的存储方式为:
arr[0, 0], arr[1, 0], ···, arr[m - 1, 0]
arr[0, 1], arr[1, 1], ···, arr[m - 1, 1]
·················
arr[0, n - 1], arr[1, n - 1], ···, arr[m - 1, n - 1]
PS:IDL的数组存储方式和我们平常了解的正好相反,是先列后行。这里有个小技巧来快速记住,可以把这个二维数组存储的过程看成是一个两个for循环的迭代过程,其中m,n就是每个循环的循环次数。举个栗子,在其他语言中,数组是先行后列,那么arr[m, n]此时的存储方式为:
arr[0, 0], arr[0, 1], ···, arr[0, n - 1]
arr[1, 0], arr[1, 1], ···, arr[1, n - 1]
·················
arr[m - 1, 0], arr[m - 1, 1], ···, arr[m - 1, n - 1]
转换成循环方式理解为(用C++的语言更清晰一点):
for (i = 0; i < m; ++i)
for (j = 0; j < n; ++j)
arr[i, j] = value;
那么在IDL中呢就是这样的:
for (i = 0; i < n; i++)
for (j = 0; j < m; j++)
arr[j, i] = value;
这个方法可以推广到IDL中三维数组的存储,比如arr[m, n, t]就可以看成:
for (i = 0; i < t; i++)
for (j = 0; j < n; j++)
for (k = 0; k < m; k++)
arr[k, j, i] = value;
总结:针对数组arr[m, n, ···],在其他语言里,你要从左往右看;在IDL里,你要从右往左看。
常用知识点:
1.数组的访问
IDL是支持负下标的。其中,-1为最后一个元素的下标,可根据下标值依次获取元素。
然而下标可以是向量,这样可以一次访问多个元素,如:
IDL> arr = indgen(8)
IDL> indices = [0, 1, 3, 5]
IDL> print, arr[indices]
0 1 3 5 5
还有一种是通过“:”方式访问多行或多列数据:
IDL> arr = indgen(5, 5)
//假如想访问第2~4列和3~5行
IDL> subarr = arr[1 : 3, 2 : 4]
IDL> help, subarr
SUBARR INT = Array[3, 3]
//假如想访问对角线元素:
//subarr = arr[indgen(n), indgen(n)] or subarr = arr[0 : (n * n - 1) : (n + 1)]
subarr = arr[indgen(5), indgen(5)]
subarr = arr[0 : (5 * 5 - 1) : (5 + 1)]
2.数组的合并
数组与数组的合并需要两个数组的行数或列数相同
①行数相同,可直接用[]
IDL> arr = indgen(2, 2)
IDL> brr = indgen(2, 2)
IDL> arr
0 1
2 3
IDL> brr
0 1
2 3
IDL> result = [arr, brr]
IDL> result
0 1 0 1
2 3 2 3
②列数相同,需要用[[],[]]
IDL> result = [[arr], [brr]]
IDL> result
0 1
2 3
0 1
2 3
3.where函数
函数where能返回数组中满足指定条件的元素下标。调用格式为:
result = Where(数组表达式[,count][,Complement = 变量1][,/L64][,NCOMPLEMENT = 变量2])
其中,关键字count返回符合指定条件的元素个数;变量1为不满足条件的数组元素下标;变量2为不满足条件的数组元素个数。
在这里呢,为了验证一下IDL中数组到底怎么处理的,我们举个例子:
IDL> arr = indgen(3, 4)
//arr是4行3列的
IDL> arr
0 1 2
3 4 5
6 7 8
9 10 11
//我们查询arr中偶数的位置
result = where((arr mod 2) eq 0, count)
IDL> result
0 2 4 6 8 10
注意,这里result是返回的索引,这里可以看出在使用where函数时,数组arr被转换成一维数组。转换的方式就是:下一行数据接着上一行数据。也就是前面说的按行存储。
4.数组转置与反转
Transpose函数可以对数组进行转置。调用格式为:
result = Transpose(数组, [p])
其中,关键字P为需要调整维数的数组列表,如果不设置,则完全反转。
这里呢,我们也看看转之后的数组存储:
IDL> arr = indgen(4, 3, 2)
IDL> arr
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
IDL> result = transpose(arr, [0, 2, 1])
IDL> help, result
RESULT INT = Array[4, 2, 3]
IDL> result
0 1 2 3
12 13 14 15
4 5 6 7
16 17 18 19
8 9 10 11
20 21 22 23
转置的话,感觉看起来有点复杂,个人理解是将数组看成个长方体,然后转换一下观看角度,然后切片。可以看出,原数组的元素顺序变了。
Reverse函数可以对数组进行反转:
Result = Reverse(数组, index[,/overwrite])
其中,关键字Index为数组的维数索引。这里指的注意的是index大于0,即从1开始。
arr = indgen(4, 3, 2)
IDL> result = reverse(arr, 1)
//行反转
IDL> result
3 2 1 0
7 6 5 4
11 10 9 8
15 14 13 12
19 18 17 16
23 22 21 20
5.数组大小调整
Reform函数可以在不改变数组元素个数的前提下改变数组的维数。调用格式为:
Result = Reform(Array, D1[, ···, D8][,关键字])
IDL> arr = indgen(4, 3, 2)
IDL> arr
0 1 2 3
4 5 6 7
8 9 10 11
12 13 14 15
16 17 18 19
20 21 22 23
IDL> result = reform(arr, 3, 4, 2)
IDL> result
0 1 2
3 4 5
6 7 8
9 10 11
12 13 14
15 16 17
18 19 20
21 22 23
IDL> result = reform(arr, 12, 2)
IDL> result
0 1 2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21
从上面的几个例子可以看出,reform转换后,存储顺序其实是没有变的,而且符合我们前面说的迭代循环的方式。
6.求不同值
Uniq函数能返回数组中相邻元素不同值的索引。注意,该函数只能发现相邻值;若不相邻,则会认为是两个值。如果先对数组进行排序,则可求出数组中包含的不同值。
IDL> arr=[1, 1, 2, 1, 3, 4, 5, 3, 4, 6]
IDL> result = uniq(arr)
IDL> arr[result]
1 2 1 3 4 5 3 4 6
Sort函数实现数组的排序功能,返回结果是排序后数组的下标索引。
//调用格式为: result = Uniq(数组[,Index])
IDL> arr(sort(arr))
1 1 1 2 3 3 4 4 5 6
IDL> result = uniq(arr, sort(arr))
IDL> arr(result)
1 2 3 4 5 6