I'm writing a pixel animation reading data from a Unit8Array holding 5 frames, 72 binaries each. Now I thought to reverse the frames to reverse animation. So my question:
Is there a way to reverse block-wise, or has anybody a creative idea, how I could do so? (I can't just run backwards, as each frame needs the info of previous)
const myArr = [1,2,3,4,5,6,7,8];
console.log(myArr.reverse());//8,7,6,5,4,3,2,1
//how to reach [7,8,5,6,3,4,1,2]?
//would work fine with 2D array,
//but don't have 2D
const my2D = [[1,2],[3,4],[5,6],[7,8]];
CodePudding user response:
This should do it:
const reversed = myArr
.map((_, i, a) => a[i ^ 1])
.reverse()
The way it works is that it maps each array element to another element with the index changed by inverting the 1 bit using XOR (for example 4^1=5, 5^1=4, 6^1=7, 7^1=6, etc.) and then reversing the whole array.
This trick can be used for any power of two: You can reverse groups of 4 elements using ^ 3
to flip the 1 and 2 bits, groups of 8 using ^ 7
to flip the 4, 2 and 1 bits and so on. (If you'd need other group sizes, you would have to use a more expensive operation like i size - 1 - 2 * (i % size)
instead.)
map
calls the callback with several arguments - the first one is the value of the element but we don't need it really, so we'll assign it to an unused variable _
. The second one is the index, and the third one is the array itself. Actually we only need the index, but with the third argument we can avoid writing the name of the array twice in the line (myArr.map((_, i) => myArr[i ^ 1])
would work too).
Note: depending on your exact use case maybe another option would be to do an array.length - i ^ 1
operation on the index when accessing the data, instead of creating a new array.
CodePudding user response:
Inspired by CherryDT's answer, it can be done with one map
call:
const arr = [1,2,3,4,5,6,7,8];
console.log(
arr.map((_, i) => arr[arr.length - i - 1 ^ 1])
);
<iframe name="sif1" sandbox="allow-forms allow-modals allow-scripts" frameborder="0"></iframe>