Related
I'm trying to do a check that the first array contains the same values of the second array.
However I'm confused about my code.
First question is: why is my code running my else statement if all letters in the first array are contained in the second? it will run 2 lines of "this is not valid"
Second question is: if my first array contains a duplicate letter it will still pass the check e.g
["a", "b" , "a", "d", "e", "f"]; even though there is two a's in the first it will see the same "a" again. Anyone know a way around this.
Sorry for my long winded questions but I hope it makes sense. Thanks :)
var letters = ["a", "b" , "c", "d", "e", "f"];
var otherLetters = ["a","b", "c" , "d", "e", "f"];
var i = -1;
while(i<=letters.length){
i++;
if(otherLetters.includes(letters[i])){
console.log("This is valid");
}
else
console.log("This is not valid");
}
You didn't close the brackets. And your loop is very confusing, please use foreach. Here is a working example:
const letters = ["a", "b" , "c", "d", "e", "f"];
const otherLetters = ["a","b", "c" , "d", "e", "f"];
letters.forEach(el => {
if (otherLetters.includes(el)) {
console.log(el + 'is valid');
} else {
console.log(el + 'is not valid');
}
});
You are trying to access array elements which are out of bounds. The script runs 8 iterations over an array with 6 elements.
Nothing to worry, cpog90.
Try this solution.
var letters = ["a", "b" , "c", "d", "e", "f"];
var otherLetters = ["a","b", "c" , "d", "e", "f"];
var i = 0;
while(i<letters.length){
if(otherLetters.includes(letters[i])){
console.log("This is valid");
}
else {
console.log("This is not valid "+i);
}
i++;
}
What went wrong in your logic?
If you declare i = -1 and while(i<=letters.length), As 6 is length of letters, 8 iterations will be done as follows.
For first iteration (i = -1), 'while' condition returns true and checks for 'a'
output: This is valid
For second iteration (i = 0), 'while' condition returns true and checks for 'b'
output: This is valid
For third iteration (i = 1), 'while' condition returns true and checks for 'c'
output: This is valid
For fourth iteration (i = 2), 'while' condition returns true and checks for 'd'
output: This is valid
For fifth iteration (i = 3), 'while' condition returns true and checks for 'e'
output: This is valid
For sixth iteration (i = 4), 'while' condition returns true and checks for 'f'
output: This is valid
For seventh iteration (i = 5), 'while' condition returns true and checks for undefined value.
output: This is not valid
For eighth iteration (i = 6), 'while' condition returns true and checks for undefined value.
output: This is not valid
First of all you have set i = -1 which is confusing since array start position is 0.
The reason your loop is running two extra times is because loop started at -1 instead of 0 and next the condition i <= length.
Since [array length = last index + 1] your loop runs extra two times.
Just to make your code work assign var i = 0 and while condition i < letters.length
Simplest solution is using lodash. It has all optimizations out-of-the-box:
var letters = ["a", "b" , "c", "d", "e", "f"];
var otherLetters = ["f", "a","b", "c" , "d", "e"];
const finalLetters = _.sortBy(letters);
const finalOtherLetters = _.sortBy(otherLetters);
if (_.isEqual(finalLetters, finalOtherLetters)) {
console.log('Two arrays are equal.');
} else {
console.log('Two arrays are not equal.');
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.min.js"></script>
Arrays are index based and starts from 0. So, the -1 and the less than letters.length check puts the code into out of bounds.
var letters = ["a", "b" , "c", "d", "e", "f"];
var otherLetters = ["a","b", "c" , "d", "e", "f"];
var i = 0;
while(i<letters.length)
{
if(otherLetters.includes(letters[i]))
{
console.log("This is valid");
}
else
{
console.log("This is not valid");
}
i++;
}
You can use a combination of Array.prototype.every with Array.prototype.includes, along with some extra guard clauses.
const areSequenceEqual = (arr1, arr2) => {
if (!arr1 || !arr2) {
return false;
}
if (arr1.length !== arr2.length) {
return false;
}
return arr1.every(x => arr2.includes(x));
};
const letters = ["a", "b", "c", "d", "e", "f"];
const otherLetters = ["a", "b", "c", "d", "e", "f"];
const someOtherLetters = ["a", "b", "c", "d", "e", "f", "g"];
console.log(areSequenceEqual(letters, otherLetters));
console.log(areSequenceEqual(letters, undefined));
console.log(areSequenceEqual(letters, someOtherLetters));
For an array like:
["abc", "bc", "dd", "d", "ee", "ff", "e"]
What would be an efficient way to get:
[["abc", "bc"],["dd", "d"],["ee", "e"]]
Explanation
["abc", "bc"] because "abc" contains "bc"
["dd", "d"] because "dd" contains "d"
["ee", "e"] because "ee" contains "e"
Any new method including parallelism is also welcomed.
You can do it using reduce(). Check if the element is included by other element. If not then add it as key of accumulator. If its included then add it to that array. At last use Object.values() to get values(arrays). Use filter() to remove arrays having length = 1
let arr = ["abc", "bc", "dd", "d", "ee", "ff", "e"]
let res = Object.values(arr.reduce((ac,a,i) => {
if(!arr.some((x,b) => x.includes(a) && i !== b)) ac[a] = [a];
else {
for(let k in ac){
if(k.includes(a)){
ac[k].push(a)
break;
}
}
}
return ac;
},{})).filter(x => x.length -1)
console.log(res)
You can loop in reverse direction and using the function splice you can drop the element and push it into the current array.
let arr = ["abc", "bc", "dd", "d", "ee", "ff", "e"];
let result = [];
for (let i = arr.length - 1; i >= 0; i--) {
let target = arr.splice(i, 1).pop();
if (target === undefined) continue;
let current = [target],
index = 0;
while ((index = arr.findIndex(s => s.includes(target))) != -1) {
current.push(arr[index]);
arr.splice(index, 1);
}
if (current.length > 1) result.push(current);
}
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
If I have a function:
function sliceArrayIntoGroups(arr, size) {
var slicedArray = arr.slice(0, size);
return slicedArray;
}
I am looking to take an array and slice it into an array of arrays.. how would I go about doing so?
So if I had this:
sliceArrayIntoGroups(["a", "b", "c", "d"], 2);
The result should be:
[["a","b"],["c","d"]]
But I don't know how to save the second part of the original array after slicing it.
Any help is appreciated.
The solution using regular while loop and custom step parameter:
function sliceArrayIntoGroups(arr, size) {
var step = 0, sliceArr = [], len = arr.length;
while (step < len) {
sliceArr.push(arr.slice(step, step += size));
}
return sliceArr;
}
console.log(sliceArrayIntoGroups(["a", "b", "c", "d"], 2));
console.log(sliceArrayIntoGroups(["a", "b", "c", "d", "e", "f"], 2));
console.log(sliceArrayIntoGroups(["a", "b", "c", "d", "e", "f"], 3));
step option points to an offset of each extraction(slicing)
This ought to do it. It's a simple recursive function that slices n elements from the beginning of the array and calls itself with the remaining elements.
function sliceArrayIntoGroups(arr, size) {
if (arr.length === 0) { return arr; }
return [ arr.slice(0, size), ...sliceArrayIntoGroups(arr.slice(size), size) ];
}
console.log(sliceArrayIntoGroups([1,2,3,4,5], 2));
console.log(sliceArrayIntoGroups([1,2,3,4,5], 3));
console.log(sliceArrayIntoGroups([1,2,3,4,5], 10));
try this, it will slice origin array to 2 pieces, then concat to 1 array
function sliceArrayIntoGroups(arr, size) {
if (size >= arr.length || size <= 0) { return arr; }
return [arr.slice(0, size), arr.slice(size)];
}
console.log(sliceArrayIntoGroups(["a", "b", "c", "d"], 2));
Try this:
function sliceArrayIntoGroups(arr, size) {
var result = [];
while (arr.length > 0) {
result.push(arr.splice(0, size));
}
return result;
}
console.log(sliceArrayIntoGroups(["a", "b", "c", "d", "e", "f"], 3));
console.log(sliceArrayIntoGroups(["a", "b", "c", "d"], 2));
function sliceArrayIntoGroups(arr, size) {
var result = [];
while (arr.length > 0) {
result.push(arr.splice(0, size));
}
return result;
}
This will divide array into pieces where each piece will be the size of size variable, so
sliceArrayIntoGroups(["a", "b", "c", "d", "e", "f"], 3);
will output
[["a", "b", "c"], ["d", "e", "f"]]
Javascript slice() method returns the selected elements in an array, as a new array object. So using for loop create smallArray and push them to arrGroup array.
function sliceArrayIntoGroups(arr, size) {
let arrGroup =[];
for (let i=0; i<arr.length; i+=size) {
let smallArray = arr.slice(i,i+size);//creating smaller array of required size using slice
arrGroup.push(smallArray);
}
return arrGroup;
}
Reduce:
var x = [1,2,3,4,5,6,7,8,9];
var chunk = function(arr,n) {
var temp;
return arr.reduce(function(carry,item,index) {
//if we're at a chunk point: index%n == 0
if(!(index%n)) {
//if temp currently holds items, push it onto carry
if(temp && temp.length) { carry.push(temp); }
//reset temp to an empty array
temp = [];
}
//push the current item onto temp
temp.push(item);
//if this is the last item in the array, push temp onto carry
index == arr.length-1 && carry.push(temp);
return carry;
},[]);
};
chunk(x,5);
I'm using regex to test certain elements in an array of arrays. If an inner array doesn't follow the desired format, I'd like to remove it from the main/outer array. The regex I'm using is working correctly. I am not sure why it isn't removing - can anyone advise or offer any edits to resolve this problem?
for (var i = arr.length-1; i>0; i--) {
var a = /^\w+$/;
var b = /^\w+$/;
var c = /^\w+$/;
var first = a.test(arr[i][0]);
var second = b.test(arr[i][1]);
var third = c.test(arr[i][2]);
if ((!first) || (!second) || (!third)){
arr.splice(i,1);
}
When you cast splice method on an array, its length is updated immediately. Thus, in future iterations, you will probably jump over some of its members.
For example:
var arr = ['a','b','c','d','e','f','g']
for(var i = 0; i < arr.length; i++) {
console.log(i, arr)
if(i%2 === 0) {
arr.splice(i, 1) // remove elements with even index
}
}
console.log(arr)
It will output:
0 ["a", "b", "c", "d", "e", "f", "g"]
1 ["b", "c", "d", "e", "f", "g"]
2 ["b", "c", "d", "e", "f", "g"]
3 ["b", "c", "e", "f", "g"]
4 ["b", "c", "e", "f", "g"]
["b", "c", "e", "f"]
My suggestion is, do not modify the array itself if you still have to iterate through it. Use another variable to save it.
var arr = ['a','b','c','d','e','f','g']
var another = []
for(var i = 0; i < arr.length; i++) {
if(i%2) {
another.push(arr[i]) // store elements with odd index
}
}
console.log(another) // ["b", "d", "f"]
Or you could go with Array.prototype.filter, which is much simpler:
arr.filter(function(el, i) {
return i%2 // store elements with odd index
})
It also outputs:
["b", "d", "f"]
Your code seems to work to me. The code in your post was missing a } to close the for statement but that should have caused the script to fail to parse and not even run at all.
I do agree with Leo that it would probably be cleaner to rewrite it using Array.prototype.filter though.
The code in your question would look something like this as a filter:
arr = arr.filter(function (row) {
return /^\w+$/.test(row[0]) && /^\w+$/.test(row[1]) && /^\w+$/.test(row[2]);
});
jsFiddle
I'm assuming it is 3 different regular expressions in your actual code, if they are all identical in your code you can save a little overhead by defining the RegExp literal once:
arr = arr.filter(function (row) {
var rxIsWord = /^\w+$/;
return rxIsWord.test(row[0]) && rxIsWord.test(row[1]) && rxIsWord.test(row[2]);
});
If Array.prototype.filter returns an array, why can't I invoke push() on this return value immediately?
Example:
var arr = ["a", "ab", "c", "ad"];
var arr2 = arr.filter(function(elmnt) { return elmnt.indexOf("a") > -1; });
// result: ["a", "ab", "ad"]
arr2.push("aaa");
// result: ["a", "ab", "ad", "aaa"]
Ok so far.
But what about chaining that push() call to the filter() call?
var arr = ["a", "ab", "c", "ad"];
var arr2 = arr.filter(function(elmnt) { return elmnt.indexOf("a") > -1; }).push("aaa");
// result: 4
Why does chaining filter() and push() result in the number of elements that I would expect, rather than an array of those elements?
The problem is not with what filter() returns, instead it is with what push() returns.
push() returns the new length of the array, and not the array itself.
So when you do:
var arr2 = arr.filter(function(elmnt) { return elmnt.indexOf("a") > -1; }).push("aaa");
arr2 will be assigned the new length of the array (which happens to be 4 in your case), and not the new array as such.
A modified version that'll do what you want would be:
var arr = ["a", "ab", "c", "ad"], arr2;
(arr2 = arr.filter(function(elmnt) { return elmnt.indexOf("a") > -1; })).push("aaa");
// now arr2 is ["a", "ab", "ad", "aaa"]
I suggest you use concat();
var arr = ["a", "ab", "c", "ad"], arr2;
(arr2 = arr.filter(function(elmnt) { return elmnt.indexOf("a") > -1; })).concat("aaa");
// now arr2 is ["a", "ab", "ad", "aaa"]
now run the above code and see the result/error.
Analyze the difference between your answer before and after running the code
Q2. correct the code so that method chain starts working
function filterOddNumbers(num) {
if (num % 2 === 0) {
return true;
} else {
return false;
}
}
const evenNumbers = [1, 2, 3, 4, 5].push().filter(filterOddNumbers);