Intercambio incondicional loco

Intercambio incondicional loco



imagen



Recientemente, me encontré con una tarea de manera inmutable para intercambiar dos elementos en una matriz por sus índices. La tarea es bastante sencilla. Por tanto, resolviéndolo de forma razonable:



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


Quería resolverlo de una manera loca. Pensé que sería interesante resolver este problema:



  • Sin operadores de comparación y operadores lógicos ( &&, ||, ...)
  • Sin bucles ni ifs ni operadores ternarios
  • Sin utilizar estructuras de datos adicionales
  • Sin casting


Reducir el problema a uno más pequeño



De hecho, esta tarea puede reducirse a una menor. Para demostrar esto, reescribamos el código de arriba de esta manera:



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

La función Math.signdevuelve el "signo" de su primer parámetro:



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