Can't seem to identify the issue (splitting an array in chunks) - javascript

So this function is supposed to split the array into chunks the size of the second argument, e.g. [1, 2, 3, 4] with the second argument 2 would return [[1, 2], [3, 4]], if the number is 3 it would return [[1, 2, 3], [4]] and so on. My function seems to be behaving in a similar way but it only returns the first chunk, and the subsequent chunks are just empty arrays. I increase the index by by the second argument after each iteration, so I'm not sure why it's not working. Can someone please explain what exactly is happening here and where is the error in the logic?
let arr = [1, 2, 3, 4, 5, 6]
function test(arr, num) {
let idx = 0;
let newArr = []
while (idx < arr.length) {
newArr.push(arr.slice(idx, num))
idx = idx + num
}
return newArr
}
console.log(test(arr, 2))

You need an index as second parameter of Array#slice, instead of the length of slice.
For example if you take the second array, index = 2 and the second parameter has to be 4, the index of the end for slicing.
chunks
values 1 2 3 4 5 6
indices 0 1 2 3 4 5
slice 0 2 1 2
2 4 3 4
4 6 5 6
function test(arr, num) {
let idx = 0;
let newArr = [];
while (idx < arr.length) {
newArr.push(arr.slice(idx, idx += num));
}
return newArr;
}
let arr = [1, 2, 3, 4, 5, 6];
console.log(test(arr, 2));

Related

Returning the first two odd numbers in an array

I have to run a code that picks out the odd numbers in an array, and returns the first two odd numbers in that array. I've figured out how to return all of the odd numbers from the array, just not the first two.
code so far:
function oddCouple(_numberList) {
let numberList = [5, 2, 3, 1];
let oddNumbers = numberList.filter((number) => number % 2 !== 0);
console.log(oddNumbers);
}
oddCouple();
Any help would be appreciated!
Array.slice returns the selected number of items from the array starting from a specified index.
function oddCouple(_numberList) {
let oddNumbers = _numberList.filter((number) => number % 2 !== 0).slice(0, 2);
console.log(oddNumbers);
}
oddCouple([1, 2, 3, 4, 5, 6, 7, 8, 9]);
The built in method would be Array.slice. This code would be suitable for a small arrays.
For larger arrays it would be more efficient to manually loop through the source array so you are only evaluating the modulus operation for the first N odd numbers.
Additionally, division is expensive. You can check if a number is odd using the binary & operator; e.g.: (number & 1) == 1
function oddCouple(_numberList) {
let numberList = [5, 2, 3, 1];
let oddNumbers = numberList.filter((number) => (number & 1) == 1).slice(0,2);
console.log(oddNumbers);
}
oddCouple();
You can use for..of loop, and break when the array contains 2 items like so:
function oddCouple(_numberList) {
let numberList = [5, 2, 3, 1];
let arr = [];
for(let number of numberList) {
(number % 2) !== 0 && arr.push(number);
if(arr.length === 2) break;
}
console.log(arr);
}
oddCouple();
function oddCouple(_numberList) {
let numberList = [5, 2, 3, 1];
let oddNumbers = numberList.filter((number) => number % 2 !== 0).slice(0,2);
console.log(oddNumbers);
}

Remove duplicates from sorted array and return length - Must mutate the original array

DISCLAIMER
I am well aware of the duplicate questions, however this one is asking to remove duplicates without making a new array and wants us to mutate the original array.
INSTRUCTIONS
Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
EXAMPLE
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
ATTEMPT
const removeDuplicates = function(nums) {
for(let i of nums){
if(nums[i] === nums[i]){
nums.splice(i, 1)
}
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
// [1, 1, 2] => [1, 2] (Correct)
// [1, 2] => [1] (Incorrect - should be [1, 2])
Am I mutating the array correctly with splice and what do I need to do to correct the 2nd argument?
Also, in leetcode, when I run the first argument, it says it's correct and returns the array of the leftover elements, but the instructions were asking for the length of the new array. Not sure if I'm missing something but why is it not returning the length?
https://imgur.com/5cuhFYf
Here you are:
const removeDuplicates = function(nums) {
for(let i = 0; i < nums.length;){
if(nums[i] === nums[++i]){
nums.splice(i, 1)
}
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
let nums = [1,1,2];
nums = [...new Set(nums)].length;
console.log(nums);
nums = [1,1,2];
nums = nums.filter(function(item, pos, self) {
return self.indexOf(item) == pos;
})
console.log(nums)
For each element of the array you need to iterate through all remaining elements of that array, to check for all duplicates. Not sure if this is more performant then making a copy.
const removeDuplicates = function (nums) {
let i = 0;
while (i < nums.length) {
let j = i + 1;
while (j < nums.length) {
if (nums[i] === nums[j]) {
nums.splice(j, 1);
}
else {
j++;
}
}
i++;
}
return nums.length;
};
console.log(removeDuplicates([1, 1, 2]));
console.log(removeDuplicates([1, 2]));
console.log(removeDuplicates([1, 2, 1, 3, 4, 3, 2, 1]));
// [1, 1, 2] => [1, 2] (Correct)
// [1, 2] => [1] (Incorrect - should be [1, 2])
// [1, 2, 1, 3, 4, 3, 2, 1] => [1, 2, 3, 4]
The hint is in the line: It doesn't matter what you leave beyond the returned length.
Whoever is asking you this wants you to move through the array keeping track of 2 pointers: 1) The end of the output array and 2) the current index in the input array.
If you do this, and copy the input to the output pointer only when they're different, you will end up with the correct output, the correct length (from the output pointer) and a little bit of garbage at the end of the array.
const unique = (arr) => {
let output = 0;
for (let input = 0; input < arr.length; input++) {
if (arr[output] !== arr[input]) {
output++;
arr[output] = arr[input];
}
}
return output + 1;
}
const arr = [1, 1, 2, 3, 3, 3, 4, 5, 5, 6, 8, 8, 8, 9, 11];
const length = unique(arr);
console.log(arr, length);
I believe this solution will pass more test cases (at least in my personal testing)
const removeDups = (nums) => {
// since mutating arrays I like to start at the end of the array so when the index is removed it doesn't impact the loop
let i = nums.length - 1;
while(i > 0){
// --i decrements then evaluates (i.e 5 === 4), i-- decriments after the evaluation (i.e 5 === 5 then decrements the last 5 to 4)
if(nums[i] === nums[--i]){
// remove the current index (i=current index, 1=number of indexes to remove including itself)
nums.splice(i,1);
}
}
console.log(nums);
return nums.length;
};
// Test Cases
console.log(removeDups([1,1,2])); // 2
console.log(removeDups([0,0,1,1,1,2,2,3,3,4])); // 5
console.log(removeDups([0,0,0,2,3,3,4,4,5,5])); // 5
Tried the solution provided by Kosh above, but it failed for bigger array [0,0,1, 1, 1, 2, 2, 3, 3, 4]. So ended up writing my own. Seems to work for all tests.
var removeDuplicates = function(nums) {
var i;
for (i = 0; i <= nums.length; i++) {
const tempNum = nums[i];
var j;
var tempIndex = [];
for (j = i+1; j <= nums.length; j++) {
if (tempNum === nums[j]) {
tempIndex.push(j)
}
}
nums.splice(tempIndex[0], tempIndex.length)
}
return (nums.length);
};

Optimize a function to iterate less into arrays

As a part of a CodeSignal challange i'm asked to :
Given a sequence of integers as an array, determine whether it is
possible to obtain a strictly increasing sequence by removing no more
than one element from the array.
For sequence = [1, 3, 2, 1], the output should be
function(sequence) = false. There is no one element in this array
that can be removed in order to get a strictly increasing sequence.
For sequence = [1, 3, 2], the output should be function(sequence) =
true. You can remove 3 from the array to get the strictly
increasing sequence [1, 2]. Alternately, you can remove 2 to get
the strictly increasing sequence [1, 3].
Guaranteed constraints:
2 ≤ sequence.length ≤ 105 &
-105 ≤ sequence[i] ≤ 105.
My code works but i'm looking for a more performant solution because the challenge has fixed the execution time limit of 4 seconds.
Here's my code:
const almostIncreasingSequence = seq => {
let i = 0;
while (i < seq.length) {
const filtred = [...seq];
// splice 1 element at index i from array
filtred.splice(i, 1);
// create a `sorted` array with only unique numbers and sort it
const sorted = [...new Set([...filtred].sort((a, b) => a - b))];
if (filtred.join("") === sorted.join("")) {
console.log(`filtred [${filtred}] ✅ sorted [${sorted}]`);
return true;
} else {
console.log(`filtred [${filtred}] 🛑 sorted [${sorted}]`);
}
i++;
}
return false;
};
// array of random numbers for testing
const testArr = Array.from({ length: 100000 }, () =>
Math.floor(Math.random() * 100)
);
// [1,,N] for testing
// const testArr = Array.apply(null, { length: 100001 }).map(Number.call, Number);
console.log(almostIncreasingSequence(testArr));
You could take a found index.
This approach tests either three consecutive elements, like
v
1 2 [3 8 4] 5 6 7 -> found at index 3
or takes for the next loop a check which omits the found value by checking the found index.
v
1 2 3 [8 4 5] 6 7
^ omit value on found index
Then if not in sequence, the adjacent items are checked to prevent this pattern
v
1 2 3 1 2 5 6 7
3 > 2
v
1 2 3 8 2 5 6 7
3 > 2
and if found, more than one element is in wrong position.
function inSequence(array) {
var i,
found;
for (i = 1; i < array.length - 1; i++) {
if ((found === i - 1 || array[i - 1] < array[i]) && array[i] < array[i + 1]) continue;
if (array[i - 1] >= array[i + 1] || found !== undefined) return false;
found = i;
}
return true;
}
console.log(inSequence([2, 1]));
console.log(inSequence([1, 2, 3]));
console.log(inSequence([2, 1, 3]));
console.log(inSequence([1, 2, 4, 3]));
console.log(inSequence([1, 2, 3, 8, 4, 5, 6, 7]));
console.log(inSequence([1, 2, 3, 8, 4, 5, 6, 9, 7]));
console.log(inSequence([2, 1, 3, 4, 5, 2]));
console.log(inSequence([1, 2, 3, 1, 2, 5, 6, 7]));
console.log(inSequence([1, 2, 3, 8, 2, 5, 6, 7]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
Loop through your array once for a worst case performance of O(n). Count the number of times the next number is less than the last (ie out of sequence) and also bomb out as soon as this has occurred more than once to improve performance where possible.
let sequenceTrue = [1, 2, 3, 4, 2, 5, 6, 7, 8, 9];
let sequenceFalse = [1, 3, 4, 2, 5, 6, 7, 8, 2, 9];
function isAlmostIncreasingSequence(sequence) {
let count = 0;
for (let index = 0; index < sequence.length && count <= 1; index++) {
if (
!!sequence[index - 1]
&& sequence[index] <= sequence[index - 1]
) {
count++;
}
}
return count <= 1;
}
console.log("should be true", isAlmostIncreasingSequence(sequenceTrue));
console.log("should be false", isAlmostIncreasingSequence(sequenceFalse));
EDIT:
improve performance of the example above by removing the first check from the for loop and manually evaluate the first item in the array.
function isAlmostIncreasingSequence(sequence) {
let count = 0;
if (sequence[1] < sequence[0]) count++;
for (let index = 1; index < sequence.length && count <= 1; index++) {
if (sequence[index] <= sequence[index - 1]) {
count++;
}
}
return count <= 1;
}

JavasScript: chunk method [duplicate]

This question already has answers here:
Split array into chunks
(73 answers)
Closed 4 years ago.
I'm trying to implement a chunk function in javascript similar to lodash chunk. It seems like i'm hitting an indexing issue relating to the count here but I can't figure it out.
// chunk array function breaks an array into chunks of defined size
// [1, 2, 3, 4, 5, 6, 7, 8]
// with size 2
// should output: [[1,2], [3,4], [5,6], [7,8]]
const testArr = [1, 2, 3, 4, 5, 6, 7, 8]
const testArr2 = [1, 2, 3, 4, 5, 6, 7]
function chunk(arr, size){
let newArr = []
let tempArr = []
let iterations;
let remainder;
if(Number.isInteger(arr.length / size)){
iterations = arr.length / size
} else {
iterations = size.toString().split('.')[0]
// how many remain?
remainder = arr.length % size
}
// theres an issue somewhere in here relating to count
let count = 0
while(count < iterations){
tempArr = []
for(let i = count; i < (size + count); i++){
tempArr.push(arr[i])
}
newArr.push(tempArr)
count++
}
// if(remainder){
// for(let i = count; i < count + remainder; i++){
// tempArr.push(arr[i])
// }
// }
return newArr
}
console.log(chunk(testArr, 2))
I'm interested in 2 different things:
Whats wrong with my code example?
How would YOU implement this better? Clearly my example is not very
clean and I'm curious how others would handle it (some .map
.reduce stuff maybe?) i tried reading lodash docs but they use a lot of internal functions that make it a little confusing.
actual output is: [ [ 1, 2 ], [ 2, 3 ], [ 3, 4 ], [ 4, 5 ] ]
output should be: [ [ 1, 2 ], [ 3, 4 ], [ 5, 6 ], [ 7, 8 ] ]
Thanks!
A simpler way to do this would be:
let size = 2;
[1, 2, 3, 4, 5, 6, 7, 8].reduce((carry, current, index) => {
// get the current array bucket. if it doesn't exist, create it.
let el = carry[Math.floor(index / size)] = carry[Math.floor(index / size)] || [];
// push the current element onto the current bucket
el.push(current);
// return our new array
return carry;
}, [])
The issue with your code is just that you need to do:
tempArr.push(arr[i + count])

Given an array of integers, output[i] = product of all elements besides itself

I know this question has floated around StackOverflow many times before, but I'm trying to wrap my head around the why one solution in particular actually works. The question in full is:
Given an array of integers, return an output array such that output[i] is equal to the product of all the elements in the array other than itself. (Solve this in O(n) without division)
The solution I've come across in JavaScript is:
function productExceptSelf(numArray) { // sample input: [2, 2, 4, 1]
var product = 1;
var size = numArray.length;
var result = [];
for (var x = 0; x < size; x++) {
result.push(product);
product = product * numArray[x];
}
// result arr: [1, 2, 4, 16]
product = 1;
for (var i = size - 1; i > -1; i--) {
result[i] = result[i] * product;
product = product * numArray[i];
}
// result arr: [8, 8, 4, 16]
return result;
}
I understand that in the first loop, the first 3 elements in the array are multiplied by the product (which pushes 1 the first time around, totaling 4 integers in the result array).
I'm not so sure I understand how looping backwards in the second loop and performing basically the same operation gives us the answer we're looking for. Is there a name for a method of this kind? I realize this is a strange question to ask, but bear with me please.
Probably illustrating the contents of the arrays at each pass through the loop would be helpful in understanding
// forwards loop through
x = 0:
product 1
result [1]
numArray[{2}, 2, 4, 1]
product after 2
x = 1
product 2
result [1, 2]
numArray[2, {2}, 4, 1]
product after 4
x = 2
product 4
result [1, 2, 4]
numArray[2, 2, {4}, 1]
product after 16
x = 3
product 16
result [1, 2, 4, 16]
numArray[2, 2, 4, {1}]
product after 16
Now the other direction
Product reset to 1
// backwards loop
i = 3
product 1
result before = [1, 2, 4, {16}]
result after = [1, 2, 4, {16}] -- (16 * 1) = 16
numArray[2, 2, 4, {1}]
product after 1 -- (1*1) = 1
i = 2
product 1
result before [1, 2, {4}, 16]
result after = [1, 2, {4}, 16] -- (4 * 1) = 4
numArray[2, 2, {4}, 1]
product after 4 -- (4*1) = 4
i = 1
product 4
result before [1, {2}, 4, 16]
result after = [1, {8}, 4, 16] -- (2 * 4) = 8
numArray[2, {2}, 4, 1]
product after 8 -- (4*2) = 8
i = 0
product 8
result before [{1}, 2, 4, 16]
result after = [{8}, 8, 4, 16] -- (1 * 8) = 8
numArray[{2}, 2, 4, 1]
product after 16 -- (8*2) = 16 (unused)
The first loop multiplies each output[i] by each numArray[j] where j < i. The second multiplies each output[i] by each numArray[j] where j > i. The end result is multiplying each output[i] by each numArray[j] where j ≠ i.

Categories

Resources