クレイジー無条件交換

クレイジー無条件交換



画像



最近、配列内の2つの要素をインデックスで交換する不変の方法でタスクに遭遇しました。タスクは非常に簡単です。したがって、合理的な方法でそれを解決します。



const swap = (arr, ind1, ind2) =>
  arr.map((e, i) => {
    if (i === ind1) return arr[ind2]
    if (i === ind2) return arr[ind1]
    return e
  })


私はそれをクレイジーな方法で解決したかった。私はこの問題を解決するのが面白いだろうと思いました:



  • 比較演算子と論理演算子がなければ(&&||、...)
  • ループとifおよび3値演算子なし
  • 追加のデータ構造を使用せずに
  • キャスティングなし


問題をより小さなものに減らす



実際、このタスクはより小さなタスクに減らすことができます。これを示すために、次のように上記のコードを書き直してみましょう。



const swap = (arr, ind1, ind2) => {
  return arr.map((elem, i) => {
    const index = i === ind1 ? ind2 : i === ind2 ? ind1 : i

    return arr[index]
  })
}


index, . — ind1, ind2. ind2 ind1. , — — index .



index getSwapIndex(i, ind1, ind2).



const getSwapIndex(i, ind1, ind2) {
  return i === ind1
     ? ind2
     : i === ind2
       ? ind1
       : i
}

const swap = (arr, ind1, ind2) => arr.map((_, i) => arr[getSwapIndex(i, ind1, ind2)])


swap . ,





— . getSwapIndex , . , 1 0. 1 , 0 .



:



type NumberBoolean = 1 | 0


""



const or = (condition1, condition2) => condition1 + condition2 - condition1 * condition2


, 1 0. "" .



or(0, 0) => 0 + 0 - 0 * 0 => 0
or(0, 1) => 0 + 1 - 0 * 1 => 1
or(1, 0) => 1 + 0 - 1 * 0 => 1
or(1, 1) => 1 + 1 - 1 * 1 => 1


, :



const or = (c1, c2) => Math.sign(c1 + c2)


Math.sign

この関数Math.signは、最初のパラメーターの「符号」を返します。



Math.sign(-23) = -1
Math.sign(0) = 0
Math.sign(42) = 1




, , .



const R =  ? R1 : R2
//   -   , R1, R2 -  .
// ,
const R = P * R1 + (1 - P) * R2
//   -       .     === true,  P    1,    === false,  P    0.


P === 0, R = 0 * R1 + (1 - 0) * R2 = R2.

P === 1, R = 1 * R1 + (1 - 1) * R2 = R1.



— .



ternary(c, r1, r2) :



function ternary(p: NumberBoolean, r1: number, r2: number): number {
  return p * r1 + (1 - p) * r2
}




. :



isEqual(a: number, b: number): NumberBoolean


:



const isEqual = (a, b) => {
  return 1 - Math.sign(Math.abs(a - b))
}


Math.abs

Math.abs :



Math.abs(-23) = 23
Math.abs(0) = 0
Math.abs(42) = 42


, , . a b — , :



isEqual(a, b)
 => 1 - Math.sign(Math.abs(a - b))
 => 1 - Math.sign(Math.abs(0))
 => 1 - Math.sign(0)
 => 1 - 0
 => 1


, :



isEqual(a, b)
 => 1 - Math.sign(Math.abs(a - b))
 => 1 - Math.sign(Math.abs( ))
 => 1 - Math.sign( ))
 => 1 - 1
 => 0


.



--



getSwapIndex :



const getSwapIndex = (i, ind1, ind2) =>
  ternary(isEqual(i, ind1), ind2, ternary(isEqual(i, ind2), ind1, i))


:



const isEqual = (a, b) => 1 - Math.sign(Math.abs(a - b))

const ternary = (p, r1, r2) => p * r1 + (1 - p) * r2

const getSwapIndex = (i, ind1, ind2) =>
  ternary(isEqual(i, ind1), ind2, ternary(isEqual(i, ind2), ind1, i))

const swap = (arr, ind1, ind2) => arr.map((_, i) => arr[getSwapIndex(i, ind1, ind2)])


, , .





, , :



const getSwapIndex = (i, ind1, ind2) => {
  const shouldSwap = or(isEqual(i, ind1), isEqual(i, ind2))

  return ternary(shouldSwap, ind1 + ind2 - i, i)
}


:







, !




All Articles