Related
In my coding class I have a homework question that I'm stuck on!
I'm using Hackerrank. I think I'm over thinking a lot of things, but I need help, I'm new at this and I'm close to crying! Haha! Sorry about the backticks idk how to format codeblocks sorry! This is Javascript btw!!
The problem:
Write a function called slice, which accepts an array, and two numbers. The function should return a new array with the elements starting at the index of the first number and going until the index of the second number. If the third parameter is greater than the length of the array, it should slice until the end of the array. Do not use the built in Array.slice() function!
The function is expected to return an INTEGER_ARRAY.
The function accepts following parameters:
INTEGER_ARRAY arr
INTEGER index
INTEGER len
the function started off as
`function slice(arr, index, len) {
}`
After looking at other forums with similar problems, I tried this, but it isn't working and I think I'm overthinking it.
`function slice(arr, index, len) {
let result = [];
from = Math.max(index, 0);
to = Math.min(len);
if((!len) || (len > arr.length)) {
for(let i = from; i<arr.length; i++) {
result.push(arr[i]);}
}
else {
for(let i = from; i<to; i++) {
result.push(arr[i]);
}
}
return result;
}`
try this once and let me know if it works, tbh I didn't got why you have written (!len).
function slice(arr, index, len) {
let result = [];
from = Math.max(index, 0);
if((!len) || ((from+len) > arr.length)) {
for(let i = from; i<arr.length; i++) {
result.push(arr[i]);}
}
else {
for(let i = from; i<from + len; i++) {
result.push(arr[i]);
}
}
return result;
}
I am trying to create a function that builds an array up to a number set by the function parameter, with an if condition on being included based on whether the remainder is zero. The last number in the array should be no higher than the parameter. Here's what I came up with so far --
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < array.length; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
When I console log this, with justThreesUpTo(20), I get --
// [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42 ]
I see the issue being setting the limiter at array.length, which maxes out the number of items that can be in the array, but I can't figure out what else to call to make sure the last number in the array goes no higher than the "num" parameter specified by the function call. Any ideas?
Setting an array's length to something before the array is populated isn't a great idea - better to just iterate over the num itself. For example
for (var i = 1; i < num; i++) {
// push to array if i % 3 === 0
Your else i won't do anything - you can just leave it off completely.
You could make your code a whole lot shorter and cleaner if you wanted:
function justThreesUpTo(num) {
const length = Math.floor(num / 3);
return Array.from({ length }, (_, i) => (i + 1) * 3);
}
console.log(justThreesUpTo(20));
Modifying an array while looping over it (or its indices, which is what you’re doing with i < array.length) is a recipe for confusion. Start with an empty array and compare with num instead:
function justThreesUpTo(num) {
var array = [];
for (var i = 1; i < num; i++) {
if (i % 3 === 0) {
array.push(i);
}
}
return array;
}
Now you can optimize the check out of that entirely by moving up the appropriate amount each time.
function justThreesUpTo(num) {
var array = [];
for (var i = 3; i < num; i += 3) {
array.push(i);
}
return array;
}
(In your original code, the entire first num holes created by array.length = num; are unused and get spliced off, and else i does nothing.)
You can try with a simple while loop
function justThreesUpTo(num) {
var array = [];
var i = 0;
while (i < num) {
if(i % 3 === 0){
array.push(i);
}
i++;
}
return array;
}
console.log(justThreesUpTo(20));
You can use map method and spread syntax in order to write a clean solution.
function justThreesUpTo(num) {
return [ ...Array(Math.floor(num/3)).keys() ].map((_,i)=> (i+1) * 3);
}
console.log(justThreesUpTo(20));
Hmm. Looks like it was a pretty simple solution. Changed the limiter from "array.length" to "num", and it worked fine.
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < num; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
Never mind!
Use while with i+=3; inside the while loop:
function justThreesUpTo(num) {
var array = [];
var i = 0;
while(i<num){
array.push(i);
i+=3;
}
return array;
}
console.log(justThreesUpTo(20));
Here's the code I wrote:
function mergeSort(array){
if(array.length < 2) return array;
var mid = Math.floor(array.length / 2);
var left = array.slice(0, mid);
var right = array.slice(mid, array.length);
return merge(mergeSort(left), mergeSort(right));
}
function merge(left, right){
var result = [];
while (left.length && right.length){
if(left[0]>right[0]){
result.push(right[0]);
} else {
result.push(left[0]);
}
}
while(left.length){
result.push(left[0]);
}
while(right.length){
result.push(right[0]);
}
return result;
}
array = [1000, -94, -115, 300, 22]
mergeSort(array);
and below is another solution i found online
function mergeSort (arr) {
if (arr.length < 2) return arr;
var mid = Math.floor(arr.length /2);
return merge(mergeSort(arr.slice(0,mid)), mergeSort(arr.slice(mid)));
}
function merge (a,b) {
var result = [];
while (a.length >0 && b.length >0)
result.push(a[0] < b[0]? a.shift() : b.shift());
return result.concat(a.length? a : b);
}
var test = [-100,3,53,21,4,0];
console.log(mergeSort(test));
in comparison I can't find any significant difference besides some syntax. But for some reason mine code won't run in both chrome dev console and node.js environment. In chrome, it won't return any result and in node.js it gives me
FATAL ERROR: CALL_AND_RETRY_LAST Allocation failed - process out of memory Abort trap: 6
Can someone help me understand what is the difference between the two snippet that actually made the difference?
Thanks in advance!
Think about it, you have an array left and you do
while(left.length){
result.push(left[0]);
}
left[0] doesn't change the array, it just gets the first item.
The length of left will never change, what you have there is a while loop that goes on as long as the array has a length over zero, and it always will, as the length never changes.
This is a perfect example of an infinite loop, that eventually fills the callstack and errors out, or in older browsers just crashes.
However if you do
while(left.length){
result.push(left.shift());
}
Array.shift() removes the first item from the array, so at some point the arrays length will be zero, and the loop stops
You never move from first element when you are doing merge. Try this code:
function mergeSort(array){
if(array.length < 2) return array;
var mid = Math.floor(array.length / 2);
var a = array.slice(0, mid);
var b = array.slice(mid);
return merge(mergeSort(a), mergeSort(b));
}
function merge(a, b){
var result = [];
var i = 0;
var j = 0;
while (i < a.length && j < b.length){
if(a[i] < b[j]){
result.push(a[i]);
i++;
} else {
result.push(b[j]);
j++;
}
}
while(i < a.length){
result.push(a[i]);
i++;
}
while(j < b.length){
result.push(b[j]);
j++
}
return result;
}
array = [1000, -94, -115, 300, 22];
array = mergeSort(array);
console.log(array);
I'm trying to work on recursion with javascript, and I'm having trouble figuring out how to do this recursively. For example, fillArray(num, len) with num = 5, and len = 3, would return [5,5,5]. I'm honestly stuck, and I haven't been able to make progress on this. It's not much, but this is what I have. Could someone please help?
var fillArray = function(num, len) {
var list = [];
if (length === 0) {
return [];
}
return list.concat(function(value, length--));
}
This can be done easier iteratively
var fillArray = function(num, len) {
var result = [];
for (var i = 0; i < len; i++) {
result.push(num);
}
return result;
}
If you really must use recursion this should work
var fillArray = function(num, len) {
if (len === 0) {
return [];
}
return [num].concat(fillArray(num, len - 1));
}
You can do it like this, but it's not very efficient to be honest.
function arrayFill(num, length){
if(length === 0) return [];
return [].concat(num, arrayFill(num, length - 1));
}
console.log(arrayFill(5, 3));
Something like this:
var fillArray = function(num, len, list) {
list.push(num);
if (list.length === len) {
return list;
} else {
return fillArray(num, len, list);
}
}
var num = 3;
var len = 3;
var list = [];
console.log(fillArray(num, len, list));
var fillArray = function(num, len) {
var result = [];
if (len > 1) result.push(fillArray(num, len - 1));
result.push(num);
return result;
}
x = fillArray(5, 3);
An example using recursion:
function fillArray( num, length) {
var array;
if( length) {
array = fillArray( num, length-1);
array.push( num);
return array;
}
else {
return [];
}
}
The recursive function calls itself with length decremented by 1 until length is zero. Then it returns an empty array. In the return path, at each level of decreasing recursion, the value of number gets pushed onto the array.
Recursion generally requires a condition to stop further recursion (here by length - 1 reaching zero), and returning the value of the recursive call ( here the value of array).
Can someone debug this code? I cannot for the life of me find the (run-time) error:
function generate_fibonacci(n1, n2, max, out){
var n = n1+n2;
if(n<max){
out.push(n);
generate_fibonacci(n2, n, max, out);
}
}
function generate_fibonacci_sequence(max){
var out = [1];
generate_fibonacci(0, 1, max, out);
return out;
}
function remove_odd_numbers(arr){
for (var i = 0; i < arr.length; i++) {
if(!(arr[i]%2==0)){
arr.splice(i, 1);
}
}
return arr;
}
function sum(array){
var total = 0;
for (var i = 0; i < array.length; i++) {
total+=array[i];
}
return total;
}
var fib_sq = generate_fibonacci_sequence(4000000);
console.log("Before: " + fib_sq);
remove_odd_numbers(fib_sq);
console.log("After: " + fib_sq);
console.log("WTH?: " + remove_odd_numbers([1,2,3,4,5,6,7,8,9]));
Output:
Before: 1,1,2,3,5,8,13,21,34,55,89,144,233,377,610,987,1597,2584,4181,6765,10946,17711,28657,46368,75025,121393,196418,317811,514229,832040,1346269,2178309,3524578
After: 1,2,5,8,21,34,89,144,377,610,1597,2584,6765,10946,28657,46368,121393,196418,514229,832040,2178309,3524578
WTH?: 2,4,6,8
[Finished in 0.3s]
I'm going crazy or something. For some reason, all odd numbers are not being removed. But as you can see at the end, it works perfectly. I have no idea what is going on.
The problem in the original code is that when you remove the first 1 at index 0, the array gets shifted; now arr[i] is contains the second 1; but you just step over it.
You need to use while instead of if here, or copy to a separate list. This is an example for splicing:
function remove_odd_numbers1(arr){
for (var i = 0; i < arr.length; i++) {
// here
while (arr[i] % 2) {
arr.splice(i, 1);
}
}
return arr;
}
But it will be slow though. Better to create a new array:
function remove_odd_numbers2(arr){
var rv = [];
for (var i = 0; i < arr.length; i++) {
if (! (arr[i] % 2)) {
rv.push(arr[i]);
}
}
return rv;
}
Generally the best algorithm however is to use the same array, if the original is not needed, so that no extra memory is required (though on javascript this is of a bit dubious value):
function remove_odd_numbers3(arr){
var out = 0;
for (var i = 0; i < arr.length; i++) {
if (! (arr[i] % 2)) {
arr[out++] = arr[i];
}
}
arr.length = out;
return arr;
}
Notice however that unlike the splice algorithm, this runs in O(n) time.
Also, the Array.prototype.filter() is not bad, being a builtin. It also creates a new array and thus is comparable to the 2.
I'm not sure about this, however I doubt using splice is efficient compared to creating a new array.
function remove_odd_numbers(arr) {
var notOdd = [],
i = 0,
len = arr.length,
num;
for (; i < len; i++) {
!((num = arr[i]) % 2) && notOdd.push(num);
}
return notOdd;
}
EDIT: You should probably use the native filter function, as suggested by #Jack. I leave this answer as a reference.
Here is a really simple, fast way to do it. Using your data, it only took 48ms to complete. Hope this helps..
function noOdds(values){
return values.filter(function (num) {
return num % 2 === 0;
});
}
Because splice() modifies the array, your index will be off in the next iteration; you need to either decrease the loop variable, use a while loop like Antti proposed or iterate backwards like Crazy Train mentioned.
That said, the use of splice() is awkward to work with because it modifies the array in-place. This functionality can be easily accomplished using a filter function as well:
function remove_odd_numbers(arr)
{
return arr.filter(function(value) {
return value % 2 == 0;
});
}
This creates and returns a new array with only the even values.
Given the recency of this function, check the compatibility section how to handle browsers IE < 9. Many popular libraries, such as jQuery, underscore, etc. take care of this for you.
Update
Instead of filtering the array afterwards, it would be more memory efficient to only add the even values as you perform the recursion:
function generate_fibonacci(previous, current, max, callback)
{
var next = previous + current;
if (next < max) {
callback(next);
generate_fibonacci(current, next, max, callback);
}
}
function generate_fibonacci_sequence(max, callback)
{
callback(1);
callback(1);
generate_fibonacci(1, 1, max, callback);
}
var out = [];
generate_fibonacci_sequence(4000000, function(value) {
if (value % 2 == 0) {
out.push(value);
}
});
Instead of passing the out array, I'm passing a function to be called whenever a new sequence value is generated; the filtering is done inside that callback.
ES6 version from "Tabetha Moe" answer
function noOdds(arr) {
return arr.filter(value => value % 2 === 0);
}