在各种语言中,都提供了多维数组。而多维数组又是很让人迷惑的一个语法结构。今天给大家聊一下多维数组使用中的一些问题。

这里,以Python和IDL为主讲解。

多维数组的概念

首先说说多维数组的概念。多维数组在不同语言中有大同小异的语法定义,但是逻辑定义上基本上一致,就是同数据类型、同逻辑含义的数据单元构成的能够用整数为坐标访问的超立方体的数据集合。

这里我用的“超立方体”,指的是数据可以表达为多个维度的下标,例如线段、矩形、立方体……它们的反例就是所谓的“参差数组”,比如下面这样的:

1, 2, 3, 4, 5

6, 7, 8

9, 1, 2, 3

这就是典型的一个参差数组,某一个维度的下标范围受到另外的维度的下标取值影响。而超立方体呢,每个维度的下标取值范围(宽度)是固定的。这个情况在python的列表嵌套、C语言动态分配实现的多维数组中都会遇到。在某些特殊情况下确实有用,但是不在这里规范化的数组讨论范围内。

第二个特点,同数据类型。正常情况下的数组都是由同类数据构成的,但是也有例外,如python的列表(list)、元组(tuple)、字典(dict),javascript中的数组,这些都是允许元素类型随意的。这种情况往往出现在脚本语言中,充分体现了语言的灵活性,但是这个真不是数组,后面会谈到。

第三个特点,同数据含义。同样的数据类型,不代表含义就相同,这个是做科学的人编程经常犯的一个毛病。典型案例就是记录数组。例如表达光谱,做一个3×n的数组,其中第一行代表波长,第二行代表流量,第三行代表误差……从语法上来说,这没错,很多光谱也是这么发布的,但是从逻辑含义上来说,我更愿意把这个东西看做3个一维数组的强行拼凑,只是因为他们的数据类型都是浮点数而已。

多维数组 VS 记录表

上面提到的最后一个情况,有些叫做二维表,我更愿意叫做记录表,以区别于二维数组。除了上面的光谱,我再举个例子:

RA

Dec

Mag_V

06:54:15.29

+56:52:09.4

16.65

22:09:38.91

-03:51:48.1

13.25

这是天文上很常见的一张记录表。这个表中,列数是固定的,每一列的含义也是独立的、固定的,但是行是可以扩展的。在numpy中,这种数据用记录(record)数组来表达,而IDL则使用结构体(structure)数组。在各种语言中基本上也都是用记录、结构体、类/对象等等来表达的。在关系型数据库中,这就是一个表。

记录表和二维数组的相似性,有这么几点:

① 都可以看做是二维的,有些语言中也确实当做二维数组访问;

② 如果各列的数据类型刚好一致(或者可以升级到相同类型),那么也可以用二维数组来装;

但是它们有本质的区别:

1,二维数组的下标之间是等价的,例如表示一幅图像时是x,y,表达矩阵是行列,可以转置、翻转,不影响其性质;而记录表的行一般表达记录,而列往往为字段,二者不可互换。

2,二维数组的大小形状和数据来源有关,是一起提供的;而记录表的列(字段)来源和行(记录)的来源是不同的。

3,二维数组不同维度的下标都是整数(或者是切片),而记录表的行是整数或切片下标,列是字段名来访问。

4,二维数组在语法上是二维的,而记录表在大部分语言的语法中,是类型为记录的一维数组。

多维数组 VS 数组的数组

这是一个很奇怪的命题……但是在许多语言的语法中确实是这样的。典型的例子:C语言。

二者从语法上来看,区别就是:前者是a[1,2],后者是a[1][2]。

出现后者的原因,主要是看语法本身的支持程度了。对于后者,有些时候是语法限制下表达多维数组的某种办法而已。例如在python中,用list或者tuple来表达多维数组的时候就是这样的。

在各种语言中,表达多维数组常数的时候,往往使用的也是数组的数组的表达方式。例如:

[ [1,2,3,4], [5,6,7,8], [9,10,11,12] ]

这实际上就是一个由3个长度为4的一维数组组成的一个“数组的数组”,但是实际表达的是3x4的二维数组。

对于数组的数组,大家要注意的就是别变成参差数组。当然参差数组也并不是坏事,它的最大特点是节约内存,例如,字符串数组,实际上就是参差数组……

还是要提一下python,它本身是不提供数组的,list/tuple都是所谓的动态数据结构。而真正的数组是通过numpy.ndarray来提供的,内部本质是面向对象加运算符重载,不过对于大家来说当做多维数组用就是了。

多维数组的存储

对于多维数组来说,逻辑上的概念中是多维的,而实际上计算机内存大家都知道是线性的,磁盘文件存储抛开柱面、磁道、扇区等等物理概念,逻辑上也是线性的。那么这二者是怎么协调的呢?

这时候,多维数组实际上被“摊平”了,变形成一维数组进行存放。这个情况下有两种方法来摊平,一种是行优先,一种是列优先,或者换句话说就是下标从左到右摊平还是从右到左。

可能听得有点晕,不过不要紧,大家只要记得会摊平就行了。不过不要以为这个操作对咱们处理数据没影响,实际上有的。举两个常见的例子:

IDL的where函数,大家基本上都用过。这个函数返回的是满足条件的元素的下标(实际上就是参数中为1的元素下标)。这时候返回的下标,就是原数组摊平之后的下标,是一维的。相对来说,np.where返回的,则是原始的下标。

在IDL中,除了多维下标的方式访问数据,也可以直接使用摊平后的一维下标来访问数据。这在各种编程语言中都是比较特殊的。

另外一个例子,如果大家在matplotlib中画直方图(hist),画的是一个二维数组的原始的分布图,就会发现很尴尬的一件事,m*n的数组,它给你画n个直方图叠在一起……因为它对每一行都去画了一个直方图。这个时候,我们就需要主动把数组摊平:plt.hist(a.flatten()),这样就把整个数组单独拿来画图了。当然用reshape也可以。

除了这两个地方不同,还有一个地方可能大家编程的时候都会被提醒的:在astropy读入的fits图像中,要选择某个像元,必须是a[y,x]。这其实也是因为数据的内部行、列优先不同造成的。

多维数组的统计

最后说一下,多维数组的统计的事情。假如有数组a,是m*n*k的,那么我们可以求出以下一系列均值:

python:

m = np.mean(a):求出全部元素的均值,是一个值

m = np.mean(a, axis=0):对第0维求均值,m是n*k的二维数组,m[i, j]是mean(a[:, i, j])

m = np.mean(a, axis=(1,2)),对第1、2维求均值,m是长为m的一维数组,m[i]是mean(a[i, :, :])

上面的例子中,选取的是前面或者后面的维度进行统计,实际上维度是可以任意组合的。

IDL也类似:

m = mean(a):求全部元素平均值。

m = mean(a, dim=1):对第1维求均值,m是n*k的数组。注意:尽管IDL的下标是从0开始的,但是在表达维度的时候,是从1开始的。其实内在原因是,dim=0的话,这个参数就会被默认当做没有赋值……

至于上面的最后那个写法,IDL不支持……

好了,就这么多了……我实在憋不出别的东西来了。有啥问题,下期再见

欢迎关注“小林在线”

一个可能有点看不懂的公号

python 二维数组长度_谈一谈多维数组相关推荐

  1. c语言数组长度可以在键盘上输入吗,C语言编程(用指针) 定义一个数组长度为10,从键盘输入数组,将每一个元素除以2后,输出数组...

    #includeint main(){int a[10]={},i,sum=0;printf("请输入10个整数:\n");for(i=0;i<10;i++){scanf(& ...

  2. python中对比数组长度_在Python中检索数组长度的首选方法

    python中对比数组长度 The __len__() is a method on container types. However, python also provides another op ...

  3. java 2维数据便利_计算机等级考试二级java数组辅导

    数组(array)是相同类型变量的集合,可以使用共同的名字引用它.数组可被定义为任何类型,可以是一维或多维.数组中的一个特别要素是通过下标来访问它.数组提供了一种将有联系的信息分组的便利方法. 注意: ...

  4. c++ 一维数组长度_每天一点C / 一维数组和指针

    哈喽,我是老吴,继续记录我的学习心得. 每天一点系列是我对微习惯的践行.现在能做到每天一点 C,将来就会有更多的每天一点系列,没人规定嵌入式软件工程师就只能学习 C 语言和折腾 Linux,不要给自己 ...

  5. vue 数组长度_深入理解Vue的数据响应式

    什么是响应式 当一个物体对外界的变化做出反应就叫响应式的,如"我打你一拳,你会喊疼". Vue的数据响应式 就是对数据做出改变时,视图上也会做出相应的变化. 举个例子 1const ...

  6. c++获取数组长度_灵魂拷问:Java如何获取数组和字符串的长度?length还是length()?...

    限时 1 秒钟给出答案,来来来,听我口令:"Java 如何获取数组和字符串的长度?length 还是 length()?" 在逛 programcreek 的时候,我发现了上面这个 ...

  7. jsp获取java数组长度_数组 – 如何在java jsp中获取数组列表大小?

    我有一个表单要求用户输入ID.此表单发送到一个servlet,该servlet检查数据库以查看用户是否存在.如果用户存在,那么它会发回我们的订购项目.有序项目作为数组列表返回.然后这个数组列表将重定向 ...

  8. 如何手动输入给数组赋值_你是否真的了解VBA数组呢?让我带你认识一下真正的数组...

    大家好,我们今日继续讲解VBA代码解决方案的第110讲内容:VBA数组讲解,什么是数组,如何定义数组,如何创建数组 一.什么是数组 就是数组共享一个名字,有着多个元素按顺序排列的变量.在数组中,元素通 ...

  9. vue 监听map数组变化_解决vue无法侦听数组及对象属性的变化问题

    一.数组 1.可以监听到的情况 如push.splice.=赋值(array=[1,2,3]) 2.无法监听到的情况 使用下标修改某个元素(这种比较常见) array[index] = 1 objec ...

最新文章

  1. C++中模块(Dll)对外暴露接口的方式
  2. 基于python的文件传输程序_7个步骤,教你快速学会用python实现ftp文件传输功能(收藏了)...
  3. CRM项目经验总结-从DAO层到链接数据池
  4. 科大星云诗社动态20210312
  5. 解决PHPCMS 安装问题 Can not connect to MySQL server
  6. 使用sklearn加载公共数据集、内存数据与CSV文件
  7. gradle 打war 包以及合并jar包
  8. kerberos的故事2
  9. Tensorflow官方文档学习理解 (三)-MNIST
  10. 自己动手做一个爬虫项目
  11. 幅相曲线渐近线_第十讲 频域分析法(Nyquist曲线)
  12. 普通话测试-短文60篇文章,附带拼音(51-60篇)
  13. 某网店营销策划方案(SWOT部分)
  14. Just Do It!
  15. 微信小程序实现素材旋转——非canvas
  16. 计算机专业学什么代码,计算机科学与技术专业代码,本科计算机科学与技术专业代码查询...
  17. 【CXY】JAVA基础 之 异常
  18. 迪杰斯特拉(Dijkstra)算法之两点之间的最短距离问题
  19. OpenCV——图像处理入门:膨胀与腐蚀、图像模糊、边缘检测
  20. QQmail安装例子

热门文章

  1. 【JMeter】Thread Group下的组件Sampler取样器
  2. yum 安装mysql数据库
  3. sqlserver如何读写操作windows系统的文件
  4. DB2表结构DDL脚本导出
  5. mysql: you can't specify target table 问题解决
  6. 网页设计表格单元格线条及边框设置
  7. 使用.NET程序集作为Business Data Connectivity数据源(二)
  8. 【心情】最近实在是太忙了,没有心情写东西!
  9. CentOS服务器下对mysql的优化
  10. URI 和 URL 的区别