array.reverse() block-wise in flat array - javascript

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]];

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.

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])
);

Related

JS function that creates a range of numbers (inclusive beginning and end) with a limit on range items

You are given a starting number and ending number and the max number of output elements allowed. How would you create an output array with as even a distribution as possible, while still including the first and last points in the output?
Function signature
function generatePoints(startingNumber, endingNumber, maxPoints) {}
Function desired output
generatePoints(0, 8, 5) // [0, 2, 4, 6, 8]
Here's what I tried so far
function generatePoints(startingNumber, endingNumber, maxPoints) {
const interval = Math.round((endingNumber - startingNumber) / maxPoints)
let count = 0
let counter = 0
let points = []
while(count < maxPoints - 1) {
points.push(counter)
counter+=interval
count++
}
points.push(endingNumber)
return points
}
Technically this creates the correct output for the simple case, but falls short when up against most other edge cases due to the fact that I'm stopping one iteration early and then adding the final point. I'm thinking that the better way to do this (to create a better distribution) is to build from the center of the array outwards, versus building from the start of the array and then stopping one element early and appending the endingNumber.
Note this:
0 2 4 6 8
+-----+ +-----+ +-----+ +-----+
A B C D
Splitting our range into intervals with 5 points including the endpoints, we have only four intervals. It will always be one fewer than the number of points. We can divide our range up evenly into these smaller ranges, simply by continually adding the width of one interval, which is just (endingNumber - startingNumber) / (maxPoints - 1). We can do it like this:
const generatePoints = (startingNumber, endingNumber, maxPoints) => Array .from (
{length: maxPoints},
(_, i) => startingNumber + i * (endingNumber - startingNumber) / (maxPoints - 1)
)
console .log (generatePoints (0, 8, 5))
We just build an array of the right length, using the index parameter to count the number of smaller intervals we're using.
We do no error-checking here, and if maxPoints were just 1, we might have an issue. But that's easy enough to handle how you like.
But there is a concern here. Why is the parameter called maxPoints instead of points? If the number of points allowed is variable, I think we need further requirements.
Do not Math.round(interval). Instead Math.round(counter) at that last moment.
The reason why is that if you've added k intervals, the error in what you're going can be as much as 0.5*k. But if you round at the last minute, the error is never more than 0.5.

Need help making a function to take in an int N and make an array with N elements. Each element should be half of the previous element starting from 1

Problem: Write a function that takes in an int n and returns a double[] of length n where the starting element (value) is 1.0 and the other elements are the previous divided by 2. For example, halves(4) should return a double[] with numbers {1.0, 0.5, 0.25, 0.125}. (JAVASCRIPT)
Stuck on where to continue, currently just have setting the array to length.
Couldn't find any questions that already answered this.
void halves(int n){
arrhalves[] n;
}
If you are writing in JavaScript, define an array with only first element [1.0]. Then, define for-loop and loop over the array n times. Starting index should be 1 (because we already have one element in the array) and on each iteration push (arr[i - 1]) / 2 to the array.

Return true if any element of array is equal to n or sum of two elements of array is equal to n - improve performance

As in title I want to return true if any element of array is equal to n or sum of two elements of array is equal to n. So if array is [1,4,5] and n is 1 or 4 or 5 or 6 or 9 I want to get true. Here's my code:
function checkArray (x, array) {
return array.includes(x) || array.some((item, i) => array.slice(i+1).includes(x-item));
}
It works fine but is using "some" the best way in terms of performance? How can I improve execution speed?
Edit: Negative numbers are allowed
There's nothing wrong with some other than the normal performance overhead of allocating/garbage collecting a function object and spinning up a function call for each and every element of the array.
It's pretty much always fastest to use a traditional for loop, but this is generally a micro-optimization that should only be used as a last resort -- refactoring from idiomatic high-level callback-driven JS code to for loop only offers a constant factor speedup.
Before resorting to that, I'd recommend lowering your time complexity: Array#includes is O(n), as is Array#slice. Doing these operations in a nested loop is O(n^2).
You can try the classic "space vs time" tradeoff and use a set to store each element you've seen so far. If n - currentElement === something in the set, you've located two numbers that sum to n.
const oneOrTwoElementsEqualN = (arr, n) => {
const seen = new Set();
return arr.some(e => {
if (e === n || seen.has(n - e)) {
return true;
}
seen.add(e);
});
};
console.log(oneOrTwoElementsEqualN([1,2,3], 5));
console.log(oneOrTwoElementsEqualN([1,2,3], 2));
console.log(oneOrTwoElementsEqualN([1,2,3], 6));
Note that this a slight variant of the "two sum" problem.

JavaScript, finding an array instance with indexOf() and lastIndexOf() methods

I'm reading "Professional JavaScript for Web Developers" (third edition) by Nicholas Zakas in an attempt to teach myself JS. However, I am having difficulty following the Location Methods section of chapter 5 on page 118 (in case you have the book). He explains that "the indexOf() method starts searching from the front of the array (item 0) and continues to the back, whereas lastIndexOf() starts from the last item in the array and continues to the front". Also he explains that "Each of these methods accepts two arguments: the item to look for and an optional index from which to start looking". He then attempts to illustrate this with examples.
As you can see below, to the right of the alert statements, he has listed what the correct output will be for each statement given the supplied argument(s). I do not understand how these outputs are determined. For example, how does alert(numbers.indexOf(4)); produce 3? I was reading this last night and thought I was just too tired to understand, however, I still cannot seem to figure out how this is achieved. I searched the Errata section from the book's companion website for a possible typo, but nothing was listed. I also searched elsewhere but found examples that mostly dealt with strings instead of numbers. Thanks for any help. This is my first post to stack overflow so my apologies if I have done something incorrect in my post.
His examples:
var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4)); //3
alert(numbers.lastIndexOf(4)); //5
alert(numbers.indexOf(4, 4)); //5
alert(numbers.lastIndexOf(4, 4)); //3
The way I thought the outcome would be:
alert(numbers.indexOf(4));
//the item in the array with the fourth index, or 5
alert(numbers.lastIndexOf(4));
//5 (this was only one that seemed to make sense to me) by counting back from the last value
alert(numbers.indexOf(4, 4));
//start looking at index 4, or 5, and then count right four places to end up at 1 (last item in array).
alert(numbers.lastIndexOf(4, 4));
//1, counting back to the left from the value with index 4, or 5, to reach the first value in the array.
Any help in determining the outputs based on the required argument and then how to also count from a specified value given the additional optional argument would be much appreciated. Thanks again.
In most of the Programming languages, default indexing start from 0. Therefore, you have an understanding problem. Double consider your example with index starting from 0.
var numbers = [1,2,3,4,5,4,3,2,1];
alert(numbers.indexOf(4)); //3, because 4 is at 3rd index
alert(numbers.lastIndexOf(4)); //5, because last 4 is at 5th index
alert(numbers.indexOf(4, 4)); //5, because searching will start from 4th index
alert(numbers.lastIndexOf(4, 4)); //3, because searching will start from last 3rd element.
JavasScript arrays are zero indexed, in other words, the first item has an index of zero. This is true for almost all programming languages (apart fro XPath for some odd reason!).
The indexOf function returns the index of the first item it finds that equals the supplied argument.
var numbers = [1,2,3,4,5,4,3,2,1];
var index = numbers.indexOf(4); // index is 3
alert(numbers[index]); // outputs 4
In JS or many other languages the index count of array starts with 0 so for,
var numbers = [1,2,3,4,5,4,3,2,1];
numbers[0] = 1
numbers[1] = 2
numbers[2] = 3
numbers[3] = 4
numbers[4] = 5
numbers[5] = 4
numbers[6] = 3
numbers[7] = 2
numbers[8] = 1
It's
indexOf("SearchString");
not
indexOf(indexNumber);
That would be awfully redundant.

How to return the 3 most and 3 less frequent numbers out of a list, elegantly

I want to use underscore for this, but for some silly reason it escapes me:
I have a list of numbers:
39, 39, 10, 1, 3, 4, 5... etc
I want to return the 3 most frequent and the 3 less frequent.
I've tried using _.countBy but that somehow returns an object, which makes it hard (?) to sort, unless perhaps I'm missing the obvious.
Call me crazy, but here is a solution without underscore, it's not particularly fast since I sort which takes O(n log n) instead of searching for the maximal three which is O(n) but if it really matters I can fix it.
Let our array be:
var arr = [1,1,1,1,1,1,2,3,4,5,6,7,7,8,9,10,9,8,9,8]
First, we reduce the numbers to their frequencies:
var t =arr.reduce(function(a,b){
a[b] = (b in a) ? a[b]+1 : 1; // set to 1 if not there, else increase
return a; // return the object
},{});
var res = Object.keys(t).sort(function(x,y){ // sort by frequency
return t[x] > t[y];
});
// Res more generally contains the frequencies ordered
alert(res[0]+" "+res[1]+" "+res[2]);
Here is a fiddle.
Ok, so I lied - I'm a sucker for native JavaScript, here is the "easier" Underscore version:
obj = _.countBy(arr,function(num){return num; }); // get array by frequencies
var res = _.keys(obj).sort(function(x,y){ return obj[x] - obj[y]});
//res is now the same as above, to be honest I like the native version better :)
Underscore fiddle if that's your thing.
First this groups them without parameters (just creates new arrays with each having the same value), and then sorts them by the resulting array lengths. Then creates two new arrays of min and max, using the first three and last three elements. .map is used to return only the first element instead of the array created by .groupBy.
EDIT: This is Benjamin Gruenbaum's slicker edit of my original answer.
var arr = [1,1,1,1,1,1,2,3,4,5,6,7,7,8,9,10,9,8,9,8];
var group = _.sortBy(_.groupBy(arr), "length");
var min = _.pluck(group.slice(0, 3),0);
var max = _.pluck(group.slice(-3),0);
console.log(min);
console.log(max);
jsFiddle

Categories