nditer

迭代器对象 numpy.nditer 提供了一种灵活访问一个或者多个数组元素的方式

访问

创建nditer对象时, 如果不指定访问方式, 默认是只读的

In [1]:
import numpy as np
In [5]:
a = np.arange(1,13).reshape(3,4)
print(a)
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]]
In [15]:
print(np.nditer(a)) # 构造了一个迭代器对象
# 顺序遍历 a
for x in np.nditer(a):
    print(x, end=', ')
# 顺序遍历其转置 a.T
print()
for x in np.nditer(a.T):
    print(x, end=', ')
# 可以看到, a 和 a.T的存储顺序是相同的, 都是在一维内存空间中顺序存储的, 这样做是为了效率
<numpy.nditer object at 0x0000000004DCF670>
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 
In [12]:
# 要使得 a.T 的存储顺序与逻辑顺序一致, 可以通过拷贝一份, 拷贝的时候指定(拷贝)存储顺序即可
b = a.T.copy()  # 默认 是以从上到下, 从左到右的顺序拷贝的
print(b)
[[ 1  5  9]
 [ 2  6 10]
 [ 3  7 11]
 [ 4  8 12]]
In [13]:
# 顺序遍历 b
for x in np.nditer(b):
    print(x, end=', ')
# 顺序遍历其转置 b.T
print()
for x in np.nditer(b.T):
    print(x, end=', ')
# 可以看到, 现在的 b, 也就是a.T, 拷贝之后其逻辑顺序与存储顺序是一致的
1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12, 
1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12, 
In [14]:
# 也可以在nditer() 中使用order参数指定遍历的顺序
# 这样 'F' 表示按照 Fortran 语言的风格, 即以 列序为主的顺序
for x in np.nditer(a, order='F'):  # 默认是'C',即C语言风格的以行序为主的格式
    print(x, end=', ')
1, 5, 9, 2, 6, 10, 3, 7, 11, 4, 8, 12, 

修改

通过指定 nditer 对象的op_flags参数值为 readwrite 或者 writeonly 来修改数组元素

In [23]:
for x in np.nditer(a, op_flags=['readwrite']):
    x[...] = x*2
print(a)
[[ 4  8 12 16]
 [20 24 28 32]
 [36 40 44 48]]

flags参数

flags 参数中的 'external_loop' 参数值可以拿到二维数组的一整行或一整列

In [29]:
for x in np.nditer(a, flags=['external_loop']):
    print(x)
[ 4  8 12 16 20 24 28 32 36 40 44 48]
In [28]:
for x in np.nditer(a, flags=['external_loop'], order='F'): # 一次获取一列
    print(x) 
[ 4 20 36]
[ 8 24 40]
[12 28 44]
[16 32 48]

广播迭代

当两个数组可以进行广播操作时, 就可以对他们进行广播迭代, 即广播与迭代同时进行

In [31]:
c = [1,2,3,4]  # 可以与a进行广播
for x, y in np.nditer([a,c]):
    print(x,y)
4 1
8 2
12 3
16 4
20 1
24 2
28 3
32 4
36 1
40 2
44 3
48 4
In [ ]: