Julia 会沿着线性索引号依次地比较两个数组中的每一个元素值,直到足以做出判断为止。

    在一般情况下,如果两个数组中同索引号的元素值都相同,并且两个数组的尺寸也相同,那么它们就一定是相等的。但是,如果我们使用的是,那么就需要特别注意了。因为这个操作符比较的是两个数组在内存中的存储地址。例如:

    1. julia> a5 = [1,1,2,3,5,8,13]; a5 === a5, a5 === [1,1,2,3,5,8,13]
    2. (true, false)
    3. julia>

    对于多维数组,操作符==!====!==以及函数isequal都依然是有效的。但是,其他的比较操作符(如<<=>>=等)就无法应用了。即使是很通用的isless函数也不能接受多维数组。

    为了解决这一问题,我们可以参考cmp函数的做法。cmp是 compare 的缩写。这个函数的功能就是比较两个值的大小。它有一个衍生方法可以比较两个一维数组。例如:

    我们可以从这个cmp方法的源码中找到灵感。该方法被定义在了 Julia 的模块里的abstractarray.jl文件中。即使我们只是把它的源码复制出来、改动一下它的参数类型,也可以满足当下的需求。就像这样:

    1. julia> import Base.cmp
    2. for (a, b) in zip(A, B)
    3. if !isequal(a, b)
    4. return isless(a, b) ? -1 : 1
    5. end
    6. end
    7. return cmp(length(A), length(B))
    8. cmp (generic function with 31 methods)
    9. julia>

    我为cmp函数定义了一个新的衍生方法。由于其中涉及到了一些我们未曾讲过的流程控制和衍生方法创建的代码,所以你在这里不用太在意它的编写细节。实际上,除了把两个参数的类型都改为Array之外,它与那个可以比较一维数组的cmp方法一模一样。

    为了测试这个方法是否可用,我还定义了一些数组:

    你最好先在心里估算一下它们谁大谁小,然后再来看下面的测试结果:

    1. julia> cmp(a6, a7), cmp(a6, a8), cmp(a6, a9), cmp(a6, a10)
    2. (-1, 1, -1, -1)

    我在前面说过,对于数组的比较,Julia 会沿着线性索引号去比较每一个对应的元素值,直到能做出判断为止。我们创建的这个cmp方法也是这么做的。因此,我们用索引表达式查看一下就可以知道原因了:

    在数组a8中,与索引号34对应的是它的第一个列向量中的后两个元素值,即:13。然而,由于数组a6中的列向量长度为2,所以其中与索引号34对应的就是其第二个列向量中的那两个元素值,即:34。所以谁大谁小也就不言自明了。这就是所谓的“沿着线性索引号比较”。这种比较不会在意数组在各个维度上的长度,而只会关注与线性索引号对应的那些元素值。

    正因为数组a6a8在第一个维度上的长度不同,所以才导致实际的比较结果与我们的直觉不一样。而其根本的原因在于,我们在做位置上的对应(或者说基于图形的对应),而 Julia 却在用线性索引号做对应。既然我们编写的是 Julia 程序,那么最好还是遵从后者。这种情况也恰恰代表了我们在编程时需要做出的一种思维转变。要想编写出优秀的程序,我们首先就要面向计算机转变思维。

    言归正传。我把相关的代码放到了Programs项目中,源码文件的相对路径为src/ch10/cmp/main.jl。其中还有一些我没在这里展示的代码,是关于函数的。你如果有兴趣的话可以先自行探究一番。