在 Smalltalk (Pharo) 中嵌套 "if"(又名 "switch")

Nested "if" (AKA "switch") in Smalltalk (Pharo)

我需要用一些值填充矩阵(存储为数组数组)。该矩阵是一个简单扩散问题的雅可比矩阵,如下所示:

J(1,1) = 1, J(N,N)=0

1<n<N:

J(n,n) = -2k/dx^2 - 2*c(n)
J(n,n-1)=J(n,n+1) = k/dx^2

其余矩阵项均为零。

到目前为止我有这个怪物:

(1 to: c size) collect: [ :n |
                (1 to: c size) collect: [ :m |
                    n = 1 | (n = c size)
                        ifTrue: [ m = n ifTrue: [ 1.0 ] ifFalse: [ 0.0 ] ]
                        ifFalse: [ m = n
                            ifTrue: [ -2.0 * k / dx squared - (2.0 * (c at: n)) ]
                            ifFalse: [ m = (n-1) | (m = (n+1))
                                ifTrue: [ k / dx squared ]
                                ifFalse: [ 0.0 ] ] ]
                    ] ]

注意嵌套的 "if-statements"(Smalltalk 等价物)。这行得通。但是,也许有更优雅的方式来做同样的事情吗?就目前而言,它是相当不可读的。

n := c size.
Matrix
  new: n
  tabulate: [:i :j | self jacobianAtRow: i column: j]

哪里

jacobianAtRow: i column: j
  n := c size.
  (i = 1 or: [i = n]) ifTrue: [^j = i ifTrue: [1.0] ifFalse [0.0]].
  j = i ifTrue: [^-2.0 * k / dx squared - (2.0 * (c at: i))].
  (j = (i - 1) or: [j = (i + 1)]) ifTrue: [^k / dx squared].
  ^0.0

基本上,一般的想法是这样的:每当你发现嵌套的 ifs 时,将那段代码单独分解成一个方法,并将嵌套转换为类似案例的枚举,returns 每个值都有一个值可能性。

为了可读性,我会考虑牺牲额外的 O(n) 时间并完全避免 IF(这只会让它更快......)。

J(N,N) = 0
J(1,1) = 1
//and for 1<n<N:
J(n,n) = Y(n)
J(n,m-1) = J(n,m+1) = X

这告诉我整个矩阵看起来像这样

( 1 X 0 0 0 )
( X Y X 0 0 )
( 0 X Y X 0 )
( 0 0 X Y X )
( 0 0 0 X 0 )

这意味着我可以创建仅包含零的整个矩阵,然后更改对角线和相邻对角线。

jNM := [ k / dx squared ].
jNN := [ :n | -2.0 * k / dx squared - (2.0 * (c at: n)) ].

n := c size.
m := Matrix
    new: n 
    tabulate: [:i :j | 0 ].
(1 to: n - 1) do: [ :i |
    m at: i at: i put: (jNN value: i).
    m at: i + 1 at: i put: jnM value.
    m at: i at: i + 1 put: jnM value.
].
m at: 1 at: 1 put: 1.

注意:我不熟悉这背后的数学原理,但 J(n,m-1) 的值对我来说似乎是一个常数。

注意 2:我将值放在 i + 1 索引处,因为我从位置 1;1 开始,但您可以从相反的方向开始并得到 i-1