I do not understand this solution - javascript

I start by pointing out that this code works. That is not the problem! I just don't understand how really. As I understand it the chunked.push method ads a new array all the time. But obviously, it does not. It gives the right answer:
[[ 1, 2], [3, 4], [5]]
I simply do not understand what is happening in this code. It spits out the right answer and put several items in each array if necessary but the code creates a new subarray each time, no? No, obviously not - but I don't understand why not? Please help!
function chunk(array, size) {
let workArr = [...array];
let chunked = [];
for (let i = 0; i < workArr.length; i++) {
let last = chunked[chunked.length - 1];
if (!last || last.length === size) {
chunked.push([workArr[i]])
} else {
last.push(workArr[i]);
}
}
return chunked;
}
Here is examples of some input parameters and expected results:
// chunk([1, 2, 3, 4], 2) --> [[ 1, 2], [3, 4]]
// chunk([1, 2, 3, 4, 5], 2) --> [[ 1, 2], [3, 4], [5]]
// chunk([1, 2, 3, 4, 5, 6, 7, 8], 3) --> [[ 1, 2, 3], [4, 5, 6], [7, 8]]
// chunk([1, 2, 3, 4, 5], 4) --> [[ 1, 2, 3, 4], [5]]
// chunk([1, 2, 3, 4, 5], 10) --> [[ 1, 2, 3, 4, 5]]

Let's break it
This copies an array there is used a spread operator
let workArr = [...array];
Iterate over every item in workArr array
for (let i = 0; i < workArr.length; i++) {
}
I think this would give you undefined at first run, because there is nothing at index -1 in chunked (because at first, chunked.length is 0), but it will set last to last element of chunked array
let last = chunked[chunked.length - 1];
If last has falsey value (0, null, undefined, "", NaN, false) or length of last equals to size (be aware, that last should be array or string), then push i-th element (indexing from 0) of workArr array into chunked array as an array, else push that element from workArr into last, but last then should be an array
if (!last || last.length === size) {
chunked.push([workArr[i]])
} else {
last.push(workArr[i]);
}
then simply return chunked array
return chunked;

Related

javascript Delete from array between 2 indices

With an array of: [1, 2, 3, 4, 5, 6]
I would like to delete between 2 indices such as 2 and 4 to produce [1, 2, null, null, 5, 6]. What's the easiest way to do this?
Hopefully better than this:
const array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]
let i = 2;
const rangeEnd = 9;
while (i < rangeEnd) {
delete array[i];
i++;
}
console.log(array)
If you want to use some native API you can actually do this with splice(). Otherwise, you should iterate a for loop through your array and change the value in each iteration.
Here is an example of how it would be done:
const array = [1, 2, 3, 4, 5, 6]
array.splice(3, 2, null, null) // the First element is beginning index and the second is count one will indicate how many indexes you need to traverse from the first one, then you should provide replace element for each of them.
console.log(array)
Note: For more info about it you can read more here.
There is a possible workaround for large scale replacement, so I will give it a touch here:
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
var anotherArr = Array(2).fill(null); // or you can simply define [null, null, ...]
Array.prototype.splice.apply(arr, [3, anotherArr.length].concat(anotherArr));
console.log(arr);
As you mean the range (2, 4] so you can follow this:
The range is: lower limit exclusive and the upper limit inclusive.
const arr = [1, 2, 3, 4, 5, 6];
const deleteRange = (arr, f, t) => {
return arr.map((item, i) => {
if (i + 1 > f && i + 1 <= t) {
return null;
}
return item;
})
}
console.log(deleteRange(arr, 2, 4));

Comparing adjacent elements in an array and selecting the smaller of each pair

I'm doing a JS algorithm course. Here is the instructor's solution for a problem, which is working successfully:
function arrayPreviousLess(items) {
const lessThanList = []
for (let i = items.length - 1; i >= 0; i--) {
for (let j = i; j >= 0; j--) {
if (items[i] > items[j]) {
lessThanList.unshift(items[j])
break
} else if (j === 0) {
lessThanList.unshift(-1)
}
}
}
return lessThanList
}
console.log(arrayPreviousLess([3, 5, 2, 4, 5]))
This code compares the adjacent array items. If the previous item is lesser than the next, it returns the lesser. In cause of false, it must return -1, like this example below:
input:
[3,5,2,4,5]
output:
[-1,3,-1,2,4]
I'm understanding everything, except what is the purpose to have break in the loop? When I deleted this break it worked the same way.
The algorithm you've shown doesn't make much sense given the problem description of adjacent pairs. There's no reason for a nested loop in addition to break unless the intent is to compare each element to all of its previous elements, in which case it's correct. Either way, unshift is much slower than push and I see no reason to resort to this function regardless of the algorithm, nor do I see the reasoning behind the reversed outer loop.
I'd write the function for adjacent pairs using map. We can do this in one iteration.
const arrayPreviousLess = a => a.map((e, i) => a[i-1] < e ? a[i-1] : -1);
[
[3, 5, 2, 4, 5],
[1],
[1, 2],
[2, 1],
[1, 2, 3],
[3, 2, 1],
[3, 2, 3],
[3, 1, 6, 4, 5],
].forEach(e => console.log(`[${e}] => [${arrayPreviousLess(e)}]`));
On the other hand, if the problem is to compare each element against all elements to its left, I'd modify the instructor's solution to at least avoid unshift and traverse the parameter array from front to back.
const arrayPreviousLess = a => a.map((e, i) => {
while (i--) {
if (a[i] < e) return a[i];
}
return -1;
});
[
[3, 5, 2, 4, 5],
[1],
[1, 2],
[2, 1],
[1, 2, 3],
[3, 2, 1],
[3, 2, 3],
[3, 1, 6, 4, 5],
].forEach(e => console.log(`[${e}] => [${arrayPreviousLess(e)}]`));
This algorithm is still quadratic but there's a linear algorithm using a stack. For each element, while the stack isn't empty and the current element is smaller than the top of the stack, pop the stack. Eventually, the stack will either become empty or its top will contain the previous smaller element. Map the element to -1 if the stack became empty, else map the element to the previous smaller element. Finally, push the current element onto the stack.
const arrayPreviousLess = a => {
const stack = [];
return a.map(e => {
while (stack.length && e < stack[stack.length-1]) {
stack.pop();
}
return stack.push(e) > 1 ? stack[stack.length-2] : -1;
});
};
[
[3, 5, 2, 4, 5],
[1],
[1, 2],
[2, 1],
[1, 2, 3],
[3, 2, 1],
[3, 2, 3],
[3, 1, 6, 4, 5],
].forEach(e => console.log(`[${e}] => [${arrayPreviousLess(e)}]`));
The intuition behind this is that any previous elements behind the current element that are greater than it can never be previous smallest candidates. We can discard them. Essentially, we're keeping a history of smallest element candidates and dropping any as soon as we can guarantee we have some smaller element ahead of it.

Array element not splicing into separate array - FreeCodeCamp > Chunky Monkey

I'm working through the FreeCodeCamp challenges and I'm stuck on the following one:
Our goal for this Algorithm is to split arr (first argument) into
smaller chunks of arrays with the length provided by size (second
argument). There are several green checks (objectives) our code needs
to pass in order to complete this Algorithm:
(['a', 'b', 'c', 'd'], 2) is expected to return [['a', 'b'], ['c', 'd']]
([0, 1, 2, 3, 4, 5], 3) is expected to return [[0, 1, 2], [3, 4, 5]]
([0, 1, 2, 3, 4, 5], 2) is expected to return [[0, 1], [2, 3], [4, 5]]
([0, 1, 2, 3, 4, 5], 4) is expected to return [[0, 1, 2, 3], [4, 5]]
([0, 1, 2, 3, 4, 5, 6, 7, 8], 2) is expected to return [[0, 1], [2, 3],
[4, 5], [6, 7], [8]].
Here is the code I've come up with:
function chunkArrayInGroups(arr, size) {
var newArray = [];
var holdArray = [];
for (var i = 0; i <= arr.length; i += size) {
holdArray = arr.slice(0, size);
removed = arr.splice(0, size);
newArray.push(holdArray);
}
if (arr.length !== 0) {
newArray.push(arr);
return newArray;
}
else return newArray;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);
The algorithm works for all of the objectives, except for the last one. Instead of returning:
[[0, 1], [2, 3], [4, 5], [6, 7], [8]]
it's returning:
[[0, 1], [2, 3], [4, 5], [6, 7, 8]] - and I can't work out why.
Any help shedding some light on where I'm going wrong would be much appreciated!
I don't blame you for being confused, it took me a while to find the problem, too.
It started with identifying that your for loop was a bit odd - you weren't using the i variable for anything. Additionally, you were splice()-ing the original array down each iteration, so your intention was correct - to wait until there is less than size elements left in the array.
So I expressed that as a while loop instead, and voila, it works:
function chunkArrayInGroups(arr, size) {
var newArray = [];
var holdArray = [];
while (arr.length >= size) {
holdArray = arr.slice(0, size);
removed = arr.splice(0, size);
newArray.push(holdArray);
}
if (arr.length !== 0) {
newArray.push(arr);
return newArray;
}
else return newArray;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);
You are recaluculating length again and again, but you forgot that you are actually removing elements from arr, so length would not be the same as size increases length decreases,either you can give as while loop or keep original length in a variable and check
function chunkArrayInGroups(arr, size) {
var newArray = [];
var holdArray = [];
var length=arr.length;
for (var i = 0; i <=length; i += size) {
holdArray = arr.slice(0, size);
removed = arr.splice(0, size);
newArray.push(holdArray);
}
if (arr.length !== 0) {
newArray.push(arr);
return newArray;
}
else return newArray;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);

Is there a more concise way to remove an entry from an array with lodash?

Below are several stabs at removing 3 from the array [8,2,3,4] using lodash. The elegant syntax for removing an object from an array of objects makes me wonder if I just haven't figured out the right approach here.
> _.remove([8,2,3,4], 3)
[]
> x = [8,2,3,4]
[8, 2, 3, 4]
> _.remove(x, 3)
[]
> x
[8, 2, 3, 4]
> _.remove(x, {3: true})
[]
> x
[8, 2, 3, 4]
> _.remove(x, [3])
[]
> x
[8, 2, 3, 4]
> _.remove(x, function(val) { return val === 3; });
[3]
> x
[8, 2, 4]
Is there another way to remove a matching element from an array that would be similar to _.remove(arrayOfObjs, {id:3})
Yes, but not using remove. You can instead use pull to remove values from an array:
Removes all provided values from array using SameValueZero for equality comparisons.
// pull modifies its argument:
x = [8, 2, 3, 4]
_.pull(x, 3)
x // => [8, 2, 4]
// pull also returns the modified array:
y = _.pull([1, 2, 3, 4, 5], 2, 3) // => [1, 4, 5]

Is there a function to find subarray in javascript with repeated elements?

I am now writing a javascript to filter out arrays that contains a specific sub-array. Of course I can write the function by myself, but I am just curious if there are already some built-in function in javascript or other javascript library to do that, or if there are easy way to do that with just a few lines.
I found that I can use underscore.js if all the elements in the sub-array is unique. There is a intersection function and I can check the lenght after intersection to see if the length are correct. However, that function fails if there are repeated values in the sub-array.
For example,
_.intersection([1, 2, 3, 4, 5], [2, 1]);
This will return [1, 2] and by checking the length I will know this array contains the sub-array.
However, when there are repeated values in the sub-array,
_.intersection([1, 1, 2, 3, 4, 7, 10], [1, 1, 2]);
_.intersection([1, 2, 3, 4], [1, 1, 2]);
Both will return [1, 2] and the cases cannot be distinguished.
Is there other pre-built function I can use or is there a easy way to do the job within a few lines?
Try this:
function contains(a, b) {
// sort arguments
if(a.length < b.length) {
var temp = a;
a = b;
b = temp;
}
// copy array
a = a.slice();
return b.every(function(elm) {
var index = a.indexOf(elm);
if(index !== -1) {
// remove the found element
a.splice(index, 1);
return true;
}
return false;
});
}
console.log(contains([1, 1, 2], [1, 2, 3, 4, 7, 10])); // logs false
console.log(contains([1, 1, 2], [1, 1, 2, 3, 4, 7, 10])); // logs true
console.log(contains([1, 2, 3, 4, 7, 10], [1, 1, 2])); // logs false
console.log(contains([1, 1, 2, 3, 4, 7, 10], [1, 1, 2])); // logs true
Here is the demo

Categories

Resources