Processing an array by sub arrays - javascript

Suppose we have an array of variable length, and I want to process it by chunks that are of a maximum length of 100, and do it in the minimum number of chunks. So for an array of length 241, it would be 3 sub arrays of sizes 41, 100, 100 (or 100, 100, 41).
curr_len = arr.length;
offset = curr_len%100;
doSomethingWithSubArray(arr.slice(offset))
for(j = offset; j <= curr_len; j = j+100){
doSomethingWithSubArray(arr.slice(j,j+100))
}
I'm sure there are more elegant ways of doing this, possibly without the special case before the for loop. Any ideas?

I'd expect the last chunk to be of smaller size. The code then would be:
for (var i=0; i<arr.length; i+=100)
doSomethingWithSubArray(arr.slice(i, 100));
This is exactly what my splitBy function does:
Array.prototype.splitBy = function(n) {
/* get: number of items per array
return: array of n-sized arrays with the items (last array may contain less then n) */
for (var r=[], i=0; i<this.length; i+=n)
r.push(this.slice(i, i+n));
return r;
}
Then write only:
arr.splitBy(100).forEach(doSomethingWithSubArray);

use chunk function~
function chunk(a, s){
for(var x, i = 0, c = -1, l = a.length, n = []; i < l; i++)
(x = i % s) ? n[c][x] = a[i] : n[++c] = [a[i]];
return n;
}
console.log(chunk([1,2,3,4,5,6,7,8,9,10], 3));

it's functional style recursive solutions.
no var, no loop, no count, because it's more cleary
var chunk = function(arr, n){
if (arr.length == 0) return [];
var head = arr.slice(0, n), rest = arr.slice(n);
return [head].concat( chunk(rest, n) );
};
console.log(chunk([1,2,3,4,5,6,7,8,9,10], 3));​

Not really, using reduce looks like this:
var array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
var splitArrays = array.reduce(function(arr, cur, i) {
if (i % 3 === 0) arr.push([]);
arr[i / 3 | 0].push(cur);
return arr;
}, []);
//splitArrays looks like:
//[[1,2,3],[4,5,6],[7,8,9],[10,11]]
More generic function
function splitArray(array, num) {
return array.reduce(function(arr, cur, i) {
if (i % num === 0) arr.push([]);
arr[i / num | 0].push(cur);
return arr;
}, []);
}

Make your doSomethingWithSubArray function accept a starting index and return a next unprocessed index or null if there's no more work. Put this "iterator" in a while loop. Do rest of work that you want to do between chunks (update UI?) right after calling this "iterator" in a while condition.

Related

Maintain the duplicates in the sum of array integers

I wrote a program to:
Print the new array of elements
Print the sum of all elements (or integers)
Actually, I got it right, however, the little problem is, I want to maintain all the duplicates (still within the range of four largest elements). Here's what I mean:
Take an array of numbers: [4,5,-2,3,1,2,6,6]
The four largest numbers are 4,5,6,6. And their sum is 4+5+6+6=21
What the code is doing (not good):
Instead of getting "6,6,5,4" as (described above), the code is printing "6,5,4,3" with the sum as 18.
ALSO, when there are only four elements [with or without duplicates] as in [1,1,1,-5],
let it just add ALL elements. You guessed it, the sum of all elements is -2
How do I order the program to print the necessary duplicate(s) to make the four largest integers?
Here's my code...
var arr = new Array(4,5,-2,3,1,2,6,6);
// var arr = new Array(1,1,1,-5);
// var largArr = new Array();
function largest() {
largArr = Array(0, 0, 0, 0)
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[0]) {
largArr[0] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[1] && arr[i] < largArr[0]) {
largArr[1] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[2] && arr[i] < largArr[1]) {
largArr[2] = arr[i];
}
}
for (i = 0; i < arr.length; i++) {
if (arr[i] > largArr[3] && arr[i] < largArr[2]) {
largArr[3] = arr[i];
}
}
console.log(largArr[0], largArr[1], largArr[2], largArr[3]);
console.log(largArr[0] + largArr[1] + largArr[2] + largArr[3]);
}
largest();
I believe there is a genius out there who can help me solve this :)
You could get the top four and filter the original array.
function get4Largest(array) {
const top4 = [...array].sort((a, b) => b - a).slice(0, 4);
return array.filter(v => {
if (top4.includes(v)) {
top4.splice(top4.indexOf(v), 1);
return true;
}
});
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
A different approach by keeping indices.
function get4Largest(array) {
return array
.map((v, i) => [v, i])
.sort(([a], [b]) => b - a)
.slice(0, 4)
.sort(([, a], [, b]) => a - b)
.map(([v]) => v);
}
console.log(get4Largest([4, 5, -2, 3, 1, 2, 6, 6]));
If you want sum of largest four numbers then you can easily do with sort, slice and reduce:
numbers.sort((a, b) => b - a).slice(0, 4).reduce((acc, curr) => acc + curr, 0)
const numbers = [4, 5, -2, 3, 1, 2, 6, 6];
const result = numbers
.sort((a, b) => b - a)
.slice(0, 4)
.reduce((acc, curr) => acc + curr, 0);
console.log(result);
You can use a reduce, sort and slice methods of an array like so:
function sumMaxValues (maxLength, values) {
return values
.sort((v1, v2) => v1 > v2 ? -1 : 1)
.slice(0, maxLength)
.reduce((sum, v) => sum + v, 0)
}
console.log(
sumMaxValues(4, [4, 5, -2, 3, 1, 2, 6, 6, 10]),
)
Edit: I fixed, a bug that #gog pointed out. The root cause of a problem was that sort when invoked without a compareFn then "the array elements are converted to strings, then sorted according to each character's Unicode code point value."(sort docs)
If for some reason you want to have a classical type of solution, that avoids modern javascript methods, here's one
const arr = Array(4, 5, -2, 3, 1, 2, 6, 6);
//const arr = Array(1, 1, 1, -5);
function largest(){
const largArr = Array(-1/0, -1/0, -1/0, -1/0);
for(let i = 0; i < arr.length; i++){
for(let j = 0; j < largArr.length; j++){
if(arr[i] > largArr[j]){
for(let k = largArr.length - 2; k >= j; k--){
largArr[k + 1] = largArr[k];
}
largArr[j] = arr[i];
break;
}
}
}
let sum = 0;
for(let j = 0; j < largArr.length; j++){
if(largArr[j] === -1/0){
largArr[j] = 0;
}
sum += largArr[j];
}
console.log(largArr, sum);
}
largest();
-1/0 stands for minus infinity (there can be no smaller number); you may also use Number.NEGATIVE_INFINITY for it. If it's too exotic for your needs, replace -1/0 with any number you are certain is less than any possible number in the array (that however, cannot be zero, since you allow negative numbers also).

How to Remove any consecutive sequence in Javascript?

I am trying to solve this.
Nominal Case:
For the array[1,2,3,5,2,4,7,54], and the number 6. The sequences[1,2,3] and [4,2] will be removed because the add up to 6. function will return [5,7,54]. If two sequences overlap, remove the first sequence.
Overlapping Case:
For the array [1,2,3,9,4,1,4,6,7] and the number 5, the sequence [2,3,] and [4,1] are removed because they add up to 5. For the [4,1] case. you see that [4,1,4] represents two overlapping sequences. because [4,1] adds up to 5 first is removed and the 4 is not removed even through [1,4] adds up to 5. We say that [4,1] and [1,4] overlap to give [4,1,4] and in those cases the first of the overlapping sequences is removed . functin will return [1,9,4,6,7]
function consecutive(arr, len, num) {
var newarr = [];
for (let i = 1; i < len; i++) {
var sum = arr[i] + arr[i + 1];
if (sum == num) {
newarr.push(arr[i]);
newarr.push(arr[i + 1]);
}
}
return newarr;
}
let arr = [1, 2, 3, 5, 2, 4, 7, 54];
let len = arr.length;
let num = 6;
console.log(consecutive(arr, len, num));
Get Wrong Output
[2,4]
You could store the target index of wrong items and if no one to filter out check the next elements if they sum up to the wanted value.
function consecutive(array, num) {
return array.filter(
(wrong => (v, i, a) => {
if (i <= wrong) return false;
let sum = 0, j = i;
while (j < a.length) {
if ((sum += a[j]) === num) {
wrong = j;
return false;
}
j++;
}
return true;
})
(-1)
);
}
console.log(consecutive([1, 2, 3, 5, 2, 4, 7, 54], 6));

Product of all other numbers in array

I have a function which takes an array of numbers as an argument. I want to return a new array with the products of each number except for the number at the current index.
For example, if arr had 5 indexes and we were creating the value for index 1, the numbers at index 0, 2, 3 and 4 would be multiplied.
Here is the code I have written:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 0;
for(let value in arr.values()) {
if(value != arr[i]) {
product *= value;
}
}
products.push(product);
}
return products;
}
getProducts([1, 7, 3, 4]);
// Output ➞ [0, 0, 0, 0]
// Expected output ➞ [84, 12, 28, 21]
As you can see, the desired output does not actualise. I did some experimenting and it appears that the second for loop is never really initiated, as any code I put inside the block does not execute:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 0;
for(let value in arr.values()) {
console.log('hello!');
if(value != arr[i]) {
product *= value;
}
}
products.push(product);
}
return products;
}
getProducts([1, 7, 3, 4]);
// Output ➞
// Expected Output ➞ 'hello!'
What is wrong with my code?
You could take the product of all numbers and divide by the number of the index to get a product of all except the actual value.
function getProducts(array) {
var product = array.reduce((a, b) => a * b, 1);
return array.map(p => product / p);
}
console.log(getProducts([1, 7, 3, 4]));
A more reliable approach with an array with one zero. If an array has more than one zero, all products are zero.
The below approach replaces the value at index with one.
function getProducts(array) {
return array.map((_, i, a) => a.reduce((a, b, j) => a * (i === j || b), 1));
}
console.log(getProducts([1, 7, 0, 4]));
console.log(getProducts([1, 7, 3, 4]));
You simply have to change the in keyword to of keyword. Is not the same a for..in than a for..of.
arr.values() returns an iterator, which has to be iterated with the of keyword.
Also, if product = 0, then all your multiplications will return 0.
By the way this code is prone to error, because you don't check the current index, but you check if the value that you are multiplying is different than the current value. This will lead to a problem if the same number is duplicated in the array.
And, now talking about good practices, is a bit weird that first you iterate through the array with a for(var i... loop and the second time you do it with a for...in/of.
I've fixed the code for you:
function getProducts(arr) {
let products = [];
for(let i = 0; i < arr.length; i++) {
let product = 1;
for(let ii = 0; ii < arr.length; ii++) {
if(i != ii) {
product *= arr[ii];
}
}
products.push(product);
}
return products;
}
A better way to do that is get the total product and use map() to divide total with each value
function getProducts(arr){
let total = arr.reduce((ac,a) => ac * a,1);
return arr.map(x => x === 0 ? total : total/x);
}
console.log(getProducts([1, 7, 3, 4]))
Explanation: replace the number at i with 1 so it doesn't interfere with the multiplication. Also, apply the fill on a copy of a hence the [...a]
console.log( [2,3,4,5].map( (n,i,a) => [...a].fill(1,i,i+1).reduce( (a,b) => a*b ) ) )

Bonfire Algorithm Challenge: Where Do I Belong on javascript

Hello guys I am currently stuck on this algorithm challenge on FCC. This is what the challenge is all about:
Return the lowest index at which a value (second argument) should be inserted into an array (first argument) once it has been sorted. The returned value should be a number.
For example, getIndexToIns([1,2,3,4], 1.5) should return 1 because it is greater than 1 (index 0), but less than 2 (index 1).
Likewise, getIndexToIns([20,3,5], 19) should return 2 because once the array has been sorted it will look like [3,5,20] and 19 is less than 20 (index 2) and greater than 5 (index 1).
This is my code here:
function getIndexToIns(arr, num) {
var getIndx;
var newArr = arr.sort(function (a, b) {
return (a - b);
});
for (i = 0; i < newArr.length; i++) {
if (num > newArr[i]) {
getIndx = newArr.indexOf(newArr[i]);
}
}
return getIndx;
}
getIndexToIns([10, 20, 30, 40, 50], 35);
when I ran the code it worked but it isn't passing the test. Guys I need your help. Thanks
The solutions proposed so far tend to follow literally the request of the problem: first sort the array, then find the index where to insert the number. That brings you to loop over the array twice. More if you have to clone the array. That is slow, even without considering all the garbage we end up creating ...
Can we do better? I think so.
How about "count how many numbers in the array are less or equal to the number to insert". This achieves the same goal but let's us do it looping only once over the array.
function getIndexToIns(arr, num) {
return arr.reduce(function (c, x) { return x <= num ? c+1 : c }, 0);
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([20,3,5], 19)); //2
console.log(getIndexToIns([1,2,3,4], 1.5)); //1
console.log(getIndexToIns([1,2,3,4], 1)); //1
console.log(getIndexToIns([1,2,3,4], 0)); //0
how about that?! twice as fast*, yay!
* it's probably not really twice as fast, if you have to be nitpicky about my claims...
EDIT
Actually I can do better. That ternary if introduces some branching in the code that bothers me. We could take advantage of javascript weirdness to avoid it
arr.reduce(function (c, x) { return c + (x <= num) }, 0)
why? because when combined with a numeric operation true is converted to 1 and false to 0
That removes the extra branching from the code so it's going to be slightly faster than the previous version ... And it would also be easier to unit test, if you care about that.
You could iterate and check if the actual value is greater then the number. Then retuen the actual index. If no value match, then return the length of the array as new input index.
function getIndexToIns(arr, num) {
var i;
arr.sort(function(a, b){
return a - b;
});
for (i = 0; i < arr.length; i++) {
if (arr[i] > num) {
return i;
}
}
return arr.length;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([1, 2, 3, 4], 1.5)); // 1
console.log(getIndexToIns([20, 3, 5], 19)); // 2
console.log(getIndexToIns([4, 3, 2, 1], 5)); // 4
Alternative version without using a method from the Array API
function getIndexToIns(array, value) {
var i = array.length,
p = 0;
while (i--) {
p += array[i] <= value;
}
return p;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([1, 2, 3, 4], 1.5)); // 1
console.log(getIndexToIns([20, 3, 5], 19)); // 2
console.log(getIndexToIns([4, 3, 2, 1], 5)); // 4
If I understand correctly I think you should look at the previous item from the list:
function getIndexToIns(arr, num) {
var getIndx = 0;
var newArr = arr.sort(function (a, b) { return (a - b); });
for (i = 1; i < newArr.length; i++) {
if (num >= newArr[i-1]) {
getIndx = i;
}
}
return getIndx;
}
console.log(getIndexToIns([10, 20, 30, 40, 50], 35)); // 3
console.log(getIndexToIns([20,3,5], 19)); //2
console.log(getIndexToIns([1,2,3,4], 1.5)); //1
console.log(getIndexToIns([1,2,3,4], 1)); //1
console.log(getIndexToIns([1,2,3,4], 0)); //0
Thanks Guys for all your assistance. I figured it out and this is the final code here
function getIndexToIns(arr, num) {
var getIndx;
var newArr = arr.sort(function(a, b){
return (a - b);
});
for (i = 0; i < newArr.length; i++) {
if (newArr[i] > num || newArr[i] === num) {
return i;
}
}
return newArr.length;
}
My solution to this problem.
const getIndexToIns = (arr, num) => {
let newArr = arr.concat(num);
newArr.sort(function(a, b) {
return a - b;
});
let index = newArr.indexOf(num);
return index;
}

Better way to turn a one-dimensional array into multi-dimensional array by required group size in JS

I am rather new to JS and I was working on a problem that asked to split an array (first argument) into groups the length of size (second argument) and returns them as a multidimensional array.
I got the problem to work right for all test cases but it suggested using the array `push()` method. I tried it multiple times and couldn't ever get it to work right. I think I was getting messed up with arrays being by reference. I eventually declared a new Array for each element. I went with a more classic deep copy each element at a time. I Didn't go back and try the `push()` method again. There has to be a more efficient way to do this. I want to write good code. Would love to see better versions please.
Thanks!
function chunk(arr, size) {
var group = 0;
var counter = 0;
var even = false;
var odd = false;
if (arr.length % size === 0) {
group = arr.length / size;
even = true;
} else {
group = Math.ceil(arr.length / size);
odd = true;
}
var newArr = new Array(group);
for (var i = 0; i < group; i++) {
newArr[i] = new Array(size);
}
for (i = 0; i < group; i++) {
for (var j = 0; j < size && counter < arr.length; j++) {
newArr[i][j] = arr[counter++];
}
}
return newArr;
}
chunk(['a', 'b', 'c', 'd'], 2);
Using Array.prototype.slice, the function can be written in a shorter way:
function chunk(array, size) {
var result = []
for (var i=0;i<array.length;i+=size)
result.push( array.slice(i,i+size) )
return result
}
You can try the slice method from the Array object. Here's an idea on how to use it.
var arr = [1, 2, 3, 4, 5, 6];
var newArr = [];
newArr.push(arr.slice(0, arr.length / 2));
newArr.push(arr.length / 2, arr.length);
This is just an shallow implementation but you can use the same concept inside a better written function.
Here's an example function:
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
function toChunks(arr, size) {
var i = 0,
chunks = [];
for (; i < arr.length; i += size) {
chunks.push(arr.slice(i, i + size););
}
return chunks;
}
toChunks(arr, 2);

Categories