Verrückter bedingungsloser Austausch

Kürzlich bin ich auf unveränderliche Weise auf eine Aufgabe gestoßen, zwei Elemente in einem Array nach ihren Indizes auszutauschen. Die Aufgabe ist ziemlich einfach. Lösen Sie es daher auf vernünftige Weise:
const swap = (arr, ind1, ind2) =>
arr.map((e, i) => {
if (i === ind1) return arr[ind2]
if (i === ind2) return arr[ind1]
return e
})
Ich wollte es auf verrückte Weise lösen. Ich dachte, es wäre interessant, dieses Problem zu lösen:
- Ohne Vergleichsoperatoren und logische Operatoren (
&&,||, ...) - Ohne Schleifen und ifs und ternäre Operatoren
- Ohne zusätzliche Datenstrukturen zu verwenden
- Kein Casting
Das Problem auf ein kleineres reduzieren
In der Tat kann diese Aufgabe auf eine kleinere reduziert werden. Um dies zu demonstrieren, schreiben wir den Code von oben folgendermaßen um:
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)
Die Funktion Math.signgibt das "Vorzeichen" ihres ersten Parameters zurück:
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(-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)
}
:
, !