Related
I've been trying to write a function which takes in an array as the first argument, then one or more other arguments which are numbers. The purpose of the function is to check whether these numbers are present in the array and remove them if so.
I have tried the following but the results haven't been what I had expected.
The desired outcome is that 3 and 2 be removed from the array leaving me with [1,4]. Instead, only 2 is removed with the end result being [1,3,4]. I've been struggling with this for a while and would appreciate any feedback you might be able to provide. I'm knew to this and this is the first problem which has left me stumped so far!
function test(myArray, ...checkNums) {
for (let num in checkNums) {
for (let num2 in myArray) {
if (myArray[num] == checkNums[num2]) {
myArray.splice(num, 1);
}
}
}
return myArray;
}
const arr = test([1, 2, 3, 4], 3, 2);
console.log({arr})
The easiest way is to just filter the array to only keep values not in checkNums. Using a Set gives better performance (depending on the implementation, lookup is either O(1) or O(log n) or anything sublinear for a Set, compared to O(n) for an Array).
function test(myArray, ...checkNums) {
const checkNumsSet = new Set(checkNums);
return myArray.filter((num) => !checkNumsSet.has(num));
}
const arr = test([1, 2, 3, 4], 3, 2);
console.log({arr})
With myArray and checkNums as arrays, you can use a filter based on .includes:
const myArray = [1,2,3,4];
const checkNums = [3,4];
const filterNums = (nums, checkNums) => {
return nums.filter(num => !checkNums.includes(num));
}
console.log(filterNums(myArray, checkNums));
Your code is removing items so your index variable is stale after you remove an element. The simplest fix is to just iterate backwards.
Also, you should avoid using for in to iterate over an array
Lastly, your array was just modifying what was passed in but you never kept a reference to it, I'm returning the modified array.
function test(myArray, ...checkNums) {
for (let checkNumsIndex = checkNums.length - 1; checkNumsIndex >=0; checkNumsIndex--) {
for (let myArrayIndex = myArray.length - 1; myArrayIndex >=0; myArrayIndex--) {
if (myArray[myArrayIndex] == checkNums[checkNumsIndex]) {
myArray.splice(myArrayIndex, 1);
}
}
}
return myArray;
}
const arr = test([1, 2, 3, 4], 3, 2);
console.log({arr});
A more straight forward is using filter and includes. This doesn't have the problem that your example has where you're testing values outside of the bounds of the array.
function removeElements(myArray, ...checkNums) {
return myArray.filter((num) => !checkNums.includes(num));
}
const arr = removeElements([1, 2, 3, 4], 3, 2);
console.log({arr});
You can use for...of see for..in vs for...of in order to iterate through your arguments, check if the number exist in your array and if yes, splice at index number
function test(myArray, ...checkNums) {
//get the elements from ...checkNums
for (let num of checkNums) {
//check if your number exist in array
if (myArray.includes(num)) {
const indexOfNum = myArray.indexOf(num);
//if it exists splice at found index of your umber
myArray.splice(indexOfNum, 1)
}
}
return myArray;
}
const result = test([1, 2, 3, 4], 3, 2);
console.log(result)
There is a problem in FreeCodeCamp.I'm not here to search solution to that problem. While trying to solve the problem I found some lines of my code do not work. I can not understand why that is not working. So I am here to ask YOU, good people, to help me.
problem
There is a function. I will pass an array and a number to that function. And what I need to return is also an array.
The array is a multidimensional array.
what I want to do
First of all I want to check if the inner or subarray contains the number i passed while calling the function. If that contains i need the index of that number in that subarray. Then I want to delete the number from that subarray using splice(). At last I wanted to return an array where there are sub arrays in it but none of them contain the given number.
where i am stuck in
But I am stuck in finding the index of the number in sub arrays, how can i use splice() to delete the number? Is it possible to do this way? Do you have any better suggestion for me?
my code
where for the first for loop it just prints -1
for the second loop, it prints the index of the array,not the index of the subarray.
function filteredArray(arr, elem) {
let newArr = [];
// Only change code below this line
newArr = [...arr]
let L = arr.length;
for (let i = 0; i < L; i++) {
// -------1-----------
for (elem in newArr[i]) {
console.log(newArr[i].indexOf(elem));
}
}
console.log('first loop ends')
for (let i = 0; i < L; i++) {
// --------2---------
for (let j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] == elem) {
console.log(newArr[i].indexOf(elem))
}
}
// Only change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
function filteredArray(arr, elem) {
let newArr = [];
// Only change code below this line
newArr = [...arr]
let L = arr.length;
// for (let i = 0; i < L; i++) {
// // -------1-----------
// for (elem in newArr[i]) {
// console.log(newArr[i].indexOf(elem));
// }
// }
console.log('first loop ends')
for (let i = 0; i < L; i++) {
// --------2---------
for (let j = 0; j < newArr[i].length; j++) {
if (newArr[i][j] == elem) {
console.log(newArr[i].indexOf(elem))
}
}
// Only change code above this line
return newArr;
}
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
When removing values from an array you don't want to use a mutating method like .splice() -- the original array will change. If .splice() removes a number, the length of the array decreases and all indexes at and after the index of the removed number will shift (unless you replace that number instead). The non-mutating methods such as filter() and .map() makes a copy of the array and returns the copy leaving the original array intact. See this article for a easy reference of what mutates and what doesn't.
You could simplify the process of removing a given number from an array of arrays by using .map() on each sub-array and .filter() each sub-array with the condition of returning only numbers that do not equal the given number.
const data = [[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]];
const filterCols = (target, arrArr) =>
arrArr.map(sub => sub.filter(num => num !== target));
console.log(filterCols(3, data));
I'm a newbie to all of this and trying to improve myself by solving problems and challenges.
I came across a problem whereby I have an unordered array which contains 8 integers.
eg [2,3,1,4,6,5,8,7]
I need to sort it [1,2,3,4,5,6,7,8] and reorder the array so that the array starts with the end value and then the first value and so on eg [8,1,7,2,6,3,5,4,]
I worked out I could use map() to iterate across the array and then use push() with pop() and shift() however it leaves the last 2 numbers behind in the original array and I'm not sure why. I got around this by using a concat and a reverse but I still don't understand why pop and shift don't bring across all the elements.
Code below that doesn't pull all the elements:
const reorder = (array) => {
let store = []
array.sort((a, b) => a - b).map((item, i) => {
if (array) {
store.push(array.pop())
store.push(array.shift())
}
})
return store
}
reorder([2, 3, 1, 4, 6, 5, 8, 7]) // returns [8,1,7,2,6,3]
Code that works but I have to add a concat and a reverse:
const reorder = (array) => {
let store = []
array.sort((a, b) => a - b).map((item, i) => {
if (array) {
store.push(array.pop())
store.push(array.shift())
}
})
return store.concat(array.reverse())
}
reorder([2, 3, 1, 4, 6, 5, 8, 7]) //returns [8,1,7,2,6,3,5,4]
Thanks for any help
I would just bisect the array, sort them in opposite orders and then add each element from each array to a new array
Given that you want to then take the sorted bisected arrays and produce another single array, I'd then use Array.prototype.reduce:
const alternatingSort = function (array) {
array = array.sort();
const midpoint = Math.round(array.length / 2)
let arr1 = array.slice(0, midpoint);
let arr2 = array.slice(midpoint);
arr2 = arr2.sort(function (a, b) { return b - a });
return arr1.reduce(function (retVal, item, index) {
arr2[index] && retVal.push(arr2[index]);
retVal.push(item);
return retVal;
}, []);
}
console.log(alternatingSort([2, 3, 1, 4, 6, 5, 8, 7]));
console.log(alternatingSort([2, 3, 1, 4, 6, 5, 8])); // with odd number
As I've seen nobody explained why the original OP solution doesn't work, Here is why:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/
Map calls a provided callback function once for each element in an array, in order, and constructs a new array from the results. callback is invoked only for indexes of the array which have assigned values (including undefined).
It is not called for missing elements of the array; that is:
1.Indexes that have never been set;
2.which have been deleted; or
3.which have never been assigned a value.
So what is happening in our code is that:
On the first iteration,
[(2), 3, 1, 4, 6, 5, 8, 7]
Map picks the first element(2) in the array, and delete the first and last characters in the array, so the array becomes
[3,(1), 4, 6, 5, 8]
Now, as map will not consider deleted elements, the second element(1) in the current array is called, also the first and last element in also removed:
[1, 4,(6), 5]
Now, map is trying to find the third element(6), and delete the first and last element:
[4,6]
Now, map is trying to find the fourth element, which is out of bound, so the map function will terminate.
So, you are strongly advised not to use Array.prototype.shift or Array.prototype.pop in Array.prototype.map.
You can do it following way:
const reorder = (array) => {
array.sort((a, b) => a - b);
const result = [];
const length = array.length;
for (let i = 0; i < length; i++) {
if (i % 2 === 0) {
result.push(array.pop());
} else {
result.push(array.shift());
}
}
return result;
}
const result = reorder([2, 3, 1, 4, 6, 5, 7]);
console.log(result);
Notice that I've intentionally made the array length to be an odd number. Some of the solutions here will break if the length is an odd number.
Personally I would sort, split in half and then just insert in. Not very fancy, but gets the job done.
function strangeWeave (arr) {
var sorted = arr.slice().sort()
var result = sorted.splice(0,Math.floor(sorted.length/2))
for (let i=0;sorted.length;i+=2) {
result.splice(i,0,sorted.pop())
}
return result
}
console.log(strangeWeave([1,2]))
console.log(strangeWeave([1,2,3]))
console.log(strangeWeave([1,2,3,4,5,6,7,8]))
console.log(strangeWeave([1,2,3,4,5,6,7,8,9]))
There is a much easier solution to sort two different arrays, one normal and one in reverse, then connect them together. Here is the code for that:
var myArray = [1, 3, 2, 4, 5, 7, 6, 8];
function getCopy(arr) {
var x = [];
for(var i = 0; i < arr.length; i++)
x.push(arr[i]);
return x;
}
function sortMyWay(arr) {
var sortedArr = [],
leftSide = getCopy(arr).sort()
.splice(0, Math.ceil(arr.length / 2)),
rightSide = getCopy(arr).sort().reverse()
.splice(0, Math.floor(arr.length / 2));
for(var i = 0; i < arr.length; i++)
i % 2
? sortedArr.push(leftSide[Math.floor(i / 2)])
: sortedArr.push(rightSide[Math.floor(i / 2)]);
console.log(sortedArr);
return sortedArr;
}
var sortedArr = sortMyWay(myArray);
Hope it helped!
Happy coding :)
function findMin(array) {
return Math.min.apply(Math, array);
}
function rearrange(matrix) {
let min = 0;
let newMatrix = [];
for (let i = 0; i < matrix.length; i++) {
let min = findMin(matrix[i]);
newMatrix[i].push(min);
}
return newMatrix;
}
Example input:
let matrix = [[2,7,1],
[0,2,0],
[1,3,1]]
rearrange(matrix);
Log:
Uncaught TypeError: Cannot read property 'push' of undefined
at reArrange (test.js:11)
at test.js:23
I'm trying to have the nested arrays sorted in an increasing order. If I didn't get it wrong, it doesn't happen because newMatrix[i] is not defined. But can't JS just create it and push the element? Do we need an extra step prior to doing this? Could you please suggest me another way, if this method won't work?
That's because you don't initialize the second dimension in your output Array. In JavaScript, if you haven't explicitly assigned to a certain element of an array, it evaluates to undefined, which obviously is neither an Array, nor an array like object and does not have a push() method.
The quickest solution to your problem should be declaring the inner arrays as well.
let newMatrix = [[], [], []];
A better, generic way would be to append an empty array to newMatrix every time you encounter a row that does not exist.
I also suspect that you algorithm is incorrect. Could you specify what exactly you intend to achieve by 'rearranging' the array? Because all your current code does is populate newMatrix with the minimum of each row. You're going to end up with [[1], [0], [1]] with the current fix. Is that intentional? Check your logic.
EDIT: Apparently, you're trying to rearrange the maxtix in such a way that the result contains each row in sorted order. Here's how to do that:
function rearrange(matrix) {
let min = 0;
let newMatrix = [];
for (let i = 0; i < matrix.length; i++) {
let sortedRow = matrix[i].sort((a, b) => a > b)
newMatrix.push(sortedRow);
}
return newMatrix;
}
console.log(rearrange([
[7, 6, 8],
[1, 9, 9],
[8, 5, 1]
]))
You need to make shure that matrix[i] is an array:
(newMatrix[i] || (newMatrix[i] = [])).push(min);
Or you set it to an array directly:
newMatrix[i] = [min];
You need to assign a new array before using Array#push
newMatrix[i] = [];
function findMin(array) {
return Math.min.apply(Math, array);
}
function rearrange(matrix) {
let min = 0;
let newMatrix = [];
for (let i = 0; i < matrix.length; i++) {
let min = findMin(matrix[i]);
newMatrix.push(min);
}
return newMatrix;
}
let matrix = [[2, 7, 1], [0, 2, 0], [1, 3, 1]];
console.log(rearrange(matrix));
.as-console-wrapper { max-height: 100% !important; top: 0; }
As an alternative solution, you could just map the result of findMin.
function findMin(array) {
return Math.min.apply(Math, array);
}
function rearrange(matrix) {
return matrix.map(findMin);
}
let matrix = [[2, 7, 1], [0, 2, 0], [1, 3, 1]];
console.log(rearrange(matrix));
Your code is not working because you miss to initialize the array before to push the min.
In your case you have newMatrix which is an empty array.
But you expect than that the array should have arrays inside:
So before this line:
newMatrix[i].push(min);
You could do:
newMatrix[i] = [];
But in this way what you are going to achieve is a new array with arrays, and each array inside has just the min of the input arrays.
If you want a new array ordered inside, you could do that in this way:
var result = [[5,3,1], [4,5,1]].reduce(function(a, b) {
a.push(b.sort());
return a;
}, []);
console.log(result);
I have two arrays where I need to compare values and get the duplicates. I wrote most of the code but seem to be stumped on the comparison.
Here is my code:
function compare(arr1, arr2) {
for (var i = 0; i< arr1.length; i++) {
for (var j = 0; j < arr2.length; j++) {
if (arr1[i] == arr2[j]) {
console.log[i];
}
}
}
}
compare([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
I get the for loops to print all of the numbers, but for some reason the if statement comparison doesn't work. Is there something I am not getting about comparing values in arrays?
I am not looking for a straight up answer but guidance if possible.
Your code is quadratic in time since it iterates the second array for each item in the first array. A linear time solution is to convert the first array into a hash table, and then, for each item in the second one, instantly check if it is in the hash.
function intersect(a, b) {
var hash = {};
a.forEach(function(x) { hash[x] = 1 });
return b.filter(function(x) { return hash[x] === 1 });
}
c = intersect([5, 3, 2, 5, 1, 6], [6, 4, 2, 7, 10]);
document.write(c)
Do note, however, that this only works if items to compare are primitives, you cannot put objects in a hash, so the code has to be quadratic:
function intersect(a, b) {
return a.filter(function(x) {
return b.indexOf(x) >= 0
});
}
a = {x:'a'};
b = {x:'b'};
c = {x:'c'};
d = {x:'d'};
i = intersect([a,b,c], [a,b,d]);
document.write(JSON.stringify(i));
Regarding your bit about improving your current code, I suggest that you make your javascript more idiomatic, in particular,
get used to iteration methods instead of for loops
check the repertoire of built-in functions and use them wherever possible
and, for sanity's sake, never ever use ==