I'm new to JS and am having trouble getting my head around the "forEach" method.
To help illustrate, let's say that I have 2 arrays.
The first: an array containing 1000 random words from the dictionary.
The second: an array containing 10 "stopwords" (words that I'd like to filter out of the first array).
If I sit down and write a function that takes these two arrays parameters, my intuition would tell me to code it like this:
function cleanSet(theSet, stoppers){
for(var i=0;i<theSet.length;i++){
for(var j=0; j<stoppers.length;j++){
if(theSet[i] === stoppers[j]){
theSet.splice(i,1);
}
}
}
return theSet;
}
However, when I try to use forEach while writing this program, it doesn't work:
function cleanerSet(theSet, stoppers){
theSet.forEach(function(setWord,i){
stoppers.forEach(function(stopper, j){
if(theSet[i] === stopper[j]){
theSet.splice(i,1);
}
});
});
return theSet;
}
Why isn't "cleanerSet" working the way "cleanSet" is?
The problem is that splice mutates your array, so you have to keep in mind that if you delete an item from the array that you are currently iterating, your index is not reset. As far as how to solve it, #Gyandeep provides a good solution. Also, in your first implementation, I think you might've meant:
theSet.splice(i,1);
I think this is what you want to do
function cleanerSet(theSet, stoppers){
return theSet.filter(function(setWord,i){
return stoppers.indexOf(setWord) === -1;
});
}
Runtime:
cleanerSet([1,2,3,4,5], [2,4]) // [1, 3, 5]
Within the callback you pass to the foreach function, the currently iterated value is stored in the first parameter of the function and the current index is stored in the second parameter. So when you check for equality you don't need to reference the index; simply use the parameter (i.e. setWord or stopper).
Additionally, when you call splice, the second parameter should be the number of items you'd like removed, so you need to pass 1, not 'i'.
This modified function should work:
function cleanerSet(theSet, stoppers){
theSet.forEach(function(setWord, i){
stoppers.forEach(function(stopper){
if(setWord === stopper){
theSet.splice(i,1);
}
});
});
return theSet;
}
Related
There is a simple function, its essence is to count from a number (n) to 0.
But when using reduce, the function just doesn't work, and no matter how I rewrite it, it returns either an empty array, or undefined, or the number itself 2.
First, I created an array that will take n, then I created a reduce method in which currentValue will take n and subtract 1 from it, after accumulator it takes the resulting number and using the push method, add it to the list array, but I don’t understand how I should add a condition that if accumulator is equal to 0, then the function must be stopped.
const countBits = (n) => {
let list = [n];
let resultReduce = n.reduce((accumulator, currentValue) => {
accumulator = currentValue - 1;
list.push(accumulator);
});
return resultReduce;
};
console.log(countBits([2]));
Why isn't this working the way I intended it to?
reduce will run on each of the items in the array, with the accumulator (first argument to the callback function) being the value that is returned from the callback function's previous iteration. So if you don't return anything, accumulator will be undefined for the next iteration.
If you want to count from n to 0, reduce is not the way to go (as well as the fact that in your current implementation, you don't even use list which would contain all of your stored numbers from n to 0). I would advise that instead, you simply loop from n to 0 and push those values into an array like so:
const countBits = (n) => {
let list = [];
for (let i = n; i > -1; i--) {
list.push(i);
}
return list;
};
console.log(countBits(2));
Also note I've changed your syntax slightly in the function call - you were passing an array with a single element seemingly unnecessarily, so I just passed the element itself to simplify the code.
The answer by Jack Bashford is correct, but for completeness I would like to point out that generating a range of numbers is a common need. Libraries like Underscore, Lodash and Ramda provide a ready-to-use function for this purpose. You don’t have to write your own implementation every time you need something common and mundane like that; save the time and enjoy the fact that you can spend your time on something more groundbreaking instead.
console.log(_.range(2, -1, -1));
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
Also for the sake of completeness, let’s consider how you might implement a downwards range function using reduce, anyway. reduce expects an input array, though it can also accept an object if using Underscore or Lodash. To make meaningful use of the input collection, we could generate a consecutive number for every element of the collection. For an array, we could of course just do _.range(collection.length - 1, -1, -1) instead, but for an object, or something that you don’t know the length of in advance, such as a generator, using reduce for this purpose might make sense. The mapDownwardsRange function below will do this:
function unshiftNext(array) {
const front = array.length ? array[0] : -1;
return [front + 1].concat(array);
}
function mapDownwardsRange(collection) {
return _.reduce(collection, unshiftNext, []);
}
console.log(mapDownwardsRange(['a', 'b', 'c']));
<script src="https://underscorejs.org/underscore-umd-min.js"></script>
I'm learning Javascript, so pardon any mistakes in how I phrase the question.
I am writing a chess program to practice and learn. Currently, I am trying to write a function to find the color of a piece with the position as the parameter. The relevant pieces of code are as follows. The first two work as they were designed to, but the last does not.
let allPieces = board.getElementsByClassName('piece');
This sets allPieces as an object with the key values the html elemnts representing each piece, both black and white.
const getPiecePosition = function(element) {
let position = window.getComputedStyle(element).getPropertyValue('grid-row-start');
let letterIndex = alphabet.findIndex(function(letter) {
return letter === position[0];
});
letterIndex += 1;
return [letterIndex, Number(position[1])];
}
This takes a parameter in the form of the allPieces object with a specific key and returns the position as an array with the column number first and the row number second. ex. [2,3].
const getPieceByPosition = function(position) {
let pce = Object.keys(allPieces).forEach(function(piece) {
if (getPiecePosition(allPieces[piece]) == position) {
return allPieces[piece].borderColor;
}
})
return pce;
}
This is the function I am having trouble with. The idea behind it is that it will take each key in the allPieces object and loop through them using forEach() into the getPiecePosition() function to compare it with the position entered as the parameter. Since only one piece can inhabit any tile at once, it should never return multiple values.
I honestly don't know where to start debugging this code, but I have been trying for about an hour. It always just returns undefined instead of a truthy value of any kind.
Your last function has a few issues:
getPiecePosition(allPieces[piece]) == position
Assuming position is an array, you're trying to compare an array with an array here using ==. However, since the two arrays are different references in memory, this will always give false, even if they contain the same elements:
console.log([2, 3] == [2, 3]); // false
You're trying to return from the callback of .forEach(). This won't achieve what you want, as return will jump out of the .forEach callback function, not your outer getPieceByPosition() function. This leads me to your final issue:
The .forEach() method doesn't return anything. That is, it doesn't evaluate to a value once it is called. This means that let pce will always be undefined since you're trying to set it to the return value of .forEach(). This, in contrast to let letterIndex, is different, as letterIndex is set to the return value of .findIndex(), which does have a return value and is determined by the function you pass it.
One additional thing you can fix up is the use of Object.keys(allPieces). While this works, it's not the best approach for looping over your elements. Ideally, you would be able to do allPieces.forEach() to loop over all your elements. However, since allPieces is a HTMLCollection, you won't be able to do that. Instead, you can use a regular for loop or a for..of loop to loop over the values in your HTMLCollection.
Alternatively, there is a way to make allPieces.forEach() work.
Instead of using board.getElementsByClassName('piece');, you can use the method .querySelectorAll('.piece'), which will give you a NodeList. Unlike a HTMLCollection, a NodeList allows you to use .forEach() on it to loop through its elements.
The return type of getElementsByClassName HTMLCollection Object. You should't use Object.keys to loop through each of 'piece' element. Insted, use the follow.
for(var i = 0 ; i < allPieces.length ; i++){
var piece = allPieces[i];
... // and, do whatever with the getPiecePosition(piece)
}
I just started learning code and i'm currently stuck on the following assignment.
Assignment:
Code a function that checks if an array contains a number by returning a boolean.(Java code)
Examples: contains([1, 2, 3, 4], 3) returns true. contains([2, 2, 4], 3) returns false.
I've tried the following:
code
Can anyone help me with solving this one?
You can use the includes() method which is available for JavaScript arrays. It will check if a specific element is included in the array and will return a boolean value of either true or false.
function contains(array, number){
var ans = array.includes(number);
return ans;
}
console.log(contains([1,2,3,4],3)); // Prints true
console.log(contains([2,2,4],3)); // Prints false
You should iterate for each array element. Considering that your array contains numbers check the following function
function contains(numberArray, check){
var i;
for (i = 0; i < numberArray.length; i++) {
if (numberArray[i] == check){
return true;
}
}
return false;
}
It takes the numberArray array as input and the check number. Then it iterates for each number in the array and checks if it finds the same number with the check number.
If it finds it, then it returns true and the loop breaks.
If it does not find it, after the loop is finished iterating all the elements of the array, then it returns false.
An array is a collection of elements of a specific type. Your function takes two parameters: the array in which you want to search, and the number you want to search.
To achieve this, you have to iterate through the array, using a controlled iteration like a for loop. The loop takes all elements in the array one by one, and performs an action that you define in the loop body, in your case you can compare the current array element to the one passed to your function. If they are the same, you can return from the loop using the return statement. If all elements were
Assuming that you're using JavaScript, you'd do something like this using the for statement:
function contains(array, number){
for(var currentElementIndex in array) {
if(array[currentElementIndex] === number) {
return true;
}
}
return false;
}
I am using mocha and chai for the first time and have no idea what is going on? im trying to say that my shuffle method has moved the array objects around and the first array object no longer - "sam1" IE -
describe('Shuffle', function(){
it('Shuffle should randomly move array items by their index', function(){
let group = ["sam1","sam2","sam3","sam4","sam5","sam6","sam7","sam8","sam9"];
let result = shuffle(group);
assert.equal(result, group[0] != "sam1");
});
});
this is the error -
AssertionError: expected [ Array(9) ] to equal true
how do i compare the two to make it true? or is there a better way to show the array has been shuffled?
The first argument of assert.equal() is where your comparison should be,
so
assert.equal(result, group[0] != "sam1");
should be
assert.equal(comparison, 'message to display on failure');
and a better way to know if the array has been shuffled would be to compare every element in the result with the original array, so something like
for(int i = 0; i < group.length; i++) {
if (group[i] !== result[i]) {
return false;
}
}
although, depending on how you shuffle there is a chance it shuffles in to the same order.
see http://www.chaijs.com/api/assert/ for more details on assert
It looks like shuffle returns an array. So to check if your first element in result array is not the same as in group array you have to compare the first two elements of arrays. If you want to use assert method, you have to do it this way:
assert(result[0] != group[0], "string if the test fails");
Just at the top of this doc
The easy way is to compare the previous array and after array. Don't use equal here but instead deepEqual to compare array or object.
it('Shuffle should randomly move array items by their index', function(){
let group = ["sam1","sam2","sam3","sam4","sam5","sam6","sam7","sam8","sam9"];
let result = shuffle(group);
assert.deepEqual(result, group);
});
});
Ref: http://www.chaijs.com/api/assert/#method_deepequal
Something like this?
assert.notEqual(group[0], "sam1");
You can find the list of usable functions here
http://www.chaijs.com/api/assert/
expect(result).to.have.members(group); // to check if all members there - doesn't care about the order
expect(result).to.not.eql(group); // to check if order has changed - there's a catch though; only 1 change on order (e.g. `shuffle` swapped **just** 2 members) is sufficient to this assertion to pass
Sources;
https://medium.com/building-ibotta/testing-arrays-and-objects-with-chai-js-4b372310fe6d
https://www.chaijs.com/api/bdd/#method_members
https://www.chaijs.com/api/bdd/#method_eql
I want to add only integers and ignore others in a particular array. I want to add this condition on that array's push event.
Array.prototype.push = function(){
if(condition){
//execute push if true
}
else
{
//return false
}
}
Help me how to code this? This affects all the array in my code. I want to check this condition on push only for a particular array. what are the ways to achieve it?
jsFiddle: http://jsfiddle.net/QhJzE/4
Add the method directly to the array:
var nums = [];
nums.push = function(n) {
if (isInt(n))
Array.prototype.push.call(this, n);
}
nums.push(2);
nums.push(3.14);
nums.push('dawg');
console.log(nums);
(See How do I check that a number is float or integer? for isInt function.)
Here's some great information: http://perfectionkills.com/how-ecmascript-5-still-does-not-allow-to-subclass-an-array/. What I've shown here is called "direct extension" in that article.