Helo. I am beginner in this JavaScript journey, and i just hit a wall. I am learning .filter() function on Array. My exercise is:
Return only the rows in the matrix that have all positive integers
I have no problems with single arrays. For example my code with single array:
function positiveRowsOnly (array) {
var result = array.filter(function (ind) {
return ind < 0;
});
return result;
};
console.log(positiveRowsOnly([1, 10, -100, 2, -20, 200, 3, 30, 300]));
its quite simple for me to understand that "ind" in .filter will accept every index from given array and check if ind < 0.
What i am struggling is if i have double arrays. Original exercise is with double arrays.
function positiveRowsOnly (array) {
var result = array.filter(function (ind) {
return ind < 0;
});
return result;
};
console.log(positiveRowsOnly([[1, 10, -100 ], [ 2, -20, 200 ], [ 3, 30, 300 ]]));
On internet i just can not find any deeper meaning how .filter() works: does filter go in one array and gets each index? Does "ind" gets just the first array and not first array index? I was looking at Math functions or indexOf but no luck. I hope you understand my struggle. Can anyone explain how this can be done or most important, how does .filter work in double arrays?
In pseudo code i know, look in array index, if it has a negative number than ignore, else return that array.
The function filter will work the same way regardless of the type of every element within an array. Basically, will loop and test a condition to filter that array.
So, you can use the function every to loop (nested arrays) and check the values from them.
+----- This is the nested array
|
| +----- This is the function 'every' that will loop
| | and check every element.
v v
ind.every(function(n) { -+
return n >= 0 |----> This is the predicate.
}); ^ -+
|
|
+----- This is the test to check every
element within the nested array.
The function every returns true when every element within an array meets a specific predicate (handler, callback, Etc,.), in your case n >= 0.
function positiveRowsOnly(array) {
var result = array.filter(function(ind) {
return ind.every(function(n) {
return n >= 0
});
});
return result;
};
console.log(positiveRowsOnly([
[1, 10, -100],
[2, -20, 200],
[3, 30, 300]
]));
.as-console-wrapper { max-height: 100% !important; top: 0; }
On internet i just can not find any deeper meaning how .filter() works: does filter go in one array and gets each index? Does "ind" gets just the first array and not first array index?
The Array.prototype.filter function will loop over the elements of an array, and pass each element to the callback function you provide (sometimes referred to as a 'predicate'). The index is actually the second argument to your predicate function.
In your case, each element of your outermost array is also an array. So your filter predicate will be passed each of the inner arrays, one at a time. If you want to filter the inner arrays, you'll need to "loop inside your loop", and call the filter function again to find the positive numbers.
Since you only want to return entire positive rows, you may want to look at other functions like Array.prototype.every, which will return a boolean if the predicate function matches. Then you could return the whole, unfiltered row.
A good trick is to try putting a console.log(ind) inside your filter functions so you can see what each element of that array looks like.
Related
While solving online code exercises, I came across this one:
Given a 1-dimensional array of numbers and the number of queries, where each query has start index a, end index b and a number c, find the sum of numbers between indexes a and b (inclusive). For each occurrence of zero within the range [a,b], add the value of c to the sum. For example, numbers = [4,6,0,10], queries = [1,3,20] => for this example we need to get the sum of [4,6,0] (indexes 1-3), and because [4,6,0] has 0, we also need to add 20.
This is my code so far:
function findSum(numbers, queries) {
//declare empty array that will store the numbers
let arr = []
// declare initial sum
let sum = 0;
// get the last element of queries (c)
let lastElement = queries[0].pop()
// loop through queries and push numbers to arr, to sum them in the end
queries[0].slice(0, 2).forEach(x => {
arr.push(numbers[x - 1])
})
// check if arr has 0
let zero = arr.filter(el => el === 0)
// if arr has 0, according to the instructions we need to add the c of the q
if (zero.length != 0) {
sum = arr.reduce((a, b) => a + b, 0) + lastElement
}
else {
sum = arr.reduce((a, b) => a + b, 0)
}
return sum
}
My code works if queries is an array, but in some test cases queries may be array of arrays like [ [ 2, 2, 20 ], [ 1, 2, 10 ] ]. I don't know know how to check the numbers in case if queries is array of arrays. Any suggestions are greatly appreciated.
in some test cases queries may be array of arrays
I would expect that this would always be the case, not just in some cases. This is also clear from your code:
queries[0].pop()
This assumes a 2-dimensional array! The problem is not that you sometimes get a 1-dimensional array and other times a 2-dimensional array. The problem is that although you always get a 2-dimensional array, your code is only looking at the first query -- the one that sits at queries[0].
Instead, you should loop over all queries.
I also assume that the return value of your function must be an array, having an answer for each of the queries. This means that you probably want to have code like this:
function findSum(numbers, queries) {
return queries.map(query => {
// solve the single query
return sum;
});
}
Note that your code is not making the sum correctly, as your arr will have a length of 2 (arr.push(numbers[x - 1]) is executed exactly twice), yet the query could indicate a range with 100 values and you should derive the sum of those 100 values, not just of two.
But even if you fix all that, you'll end up with an inefficient solution that will have to iterate over many values in the input array multiple times. This needs a smarter approach.
Try to think of a way to analyse the input before processing any queries yet. Would there be something useful you could build that would help to quickly get a sum of a subarray without having to iterate that subsection again?
Here are some hints:
Hint #1
Use the following truth:
sum(numbers.slice(start, end)) == sum(numbers.slice(0, end)) - sum(numbers.slice(0, start - 1))
Hint #2
What if you would know the sum from the start of the array to any given index? Like a running sum... So for numbers=[4, 8, 0, 3] you would know [4, 12, 12, 15]. Would that help in calculating a sum for a certain range of [start, end]?
Hint #3
How could you apply the same principle for the special treatment of zeroes?
I have a quick question about finding the difference between two arrays. I found a chunk of JavaScript code that does what I want here and modified it a bit:
JS
function diffArray(arr1, arr2) {
var newArr = [];
var myArr = arr1.concat(arr2);
newArr = myArr.filter(function(item){
return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
});
return newArr;
}
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
However, I'm not sure that I really understand what the filter function is doing here. Could anyone give me a clear explanation of how this works.
Note: I already know the basics of filter functions. I'm looking for a specfic explanation of this filter.
newArr = myArr.filter(function(item){
return arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0;
});
The Array#filter function iterates over each element of the newly made array from concat function (containing every element from arr1 and arr2 arrays).
If at least one of the conditions arr2.indexOf(item) < 0 or arr1.indexOf(item) < 0 is fulfilled (returns true) at some iteration, the Array#filter function filters out (returns) that specified (actually iterated) element.
In case, if the iterated element is both in arr1 and arr2, the indexOf function will return it's index (which is higher than 0) - the condition will return false (it's not smaller than 0). We will receive then false || false which is false and that element won't be included in the newArr array, containing unique elements.
In case, if given element is only in one array (it doesn't exist in the second one - it's index will return -1 - it will fulfill the < 0 condition) - one of the conditions will return true, so the both conditions will become true || false which is true - given element will be included in the newArr array.
Filter is using a lambda to filter the list.
This essentially means that it executes the code between the { } and returns an array that meets the criteria. Your criteria are that the index of the item is greater than 0 in both arrays which is essentially just saying it's in both arrays.
you can read more here: https://www.w3schools.com/jsref/jsref_filter.asp
Easy way of thinking this is that filter function is internally creating an array.
The elements of this internal array are the ones that pass the condition in the callback function. This is possible since this decision is being made one element at a time in the callback function.
Condition arr2.indexOf(item) < 0 || arr1.indexOf(item) < 0 passes only for element 4 since at that time 4 is not present inside arr1. Since true is returned element 4 is added in the internal array. Ultimately 4 is returned in newArr.
it's my first question here, after have been reading for years, so be nice with me please.
I'm having trouble with array management in js/jq.
I have array with several elements, which is processed with $.each function.
I want to extract matching elements to another array and return this array.
But for some reason (don't know if it's because array declaration, jquery.each function...) I'm having first empty element.
I think I'm making this more difficult to understand than it's, so made jsfiddle.
var arr = new Array();
$.each([1,2,3], function(index,element){
if (element == 2){
arr[index] = element;
}
});
arr must have only 1 element, but arr.length returns 2 because first array slot is empty.
Here is a fiddle http://jsfiddle.net/moay7y95/
I'm so sure that it's a simple and little stupid thing, but I've not been able to find an answer.
Thanks in advance!
You are pushing an element in array at 1st index. So, javascript by default put undefined at 0th index.
So, at the end of each your array will be
[undefined, 2];
This is the reason you get the length as 2.
You can use push to add element in array:
$.each([1, 2, 3], function (index, element) {
if (element == 2) {
arr.push(element);
elem++;
}
});
Demo: https://jsfiddle.net/tusharj/moay7y95/2/
The push() method adds one or more elements to the end of an array and returns the new length of the array.
Docs: https://developer.mozilla.org/en/docs/Web/JavaScript/Reference/Global_Objects/Array/push
Best solution: Use .filter
var arr = [1, 2, 3].filter(function(value){
return value == 2
});
If the return value is true, the element is included in the returned array, otherwise it is ignored. This is pure js, so you don't need jquery. See documentation about .filter
Your problem: Use .push
Try using the .push method on the array (see Mozilla's documentation).
var arr = new Array();
$.each([1,2,3], function(index,element){
if (element == 2){
arr.push(element);
}
});
The .push method will dynamically grow your array as elements are added.
Your problem is that the value of index inside your function is a reference point in your initial array. This means that if you look at the returned array, you will find [undefined, 2] and so the length is returning as 2. If your condition were element == 3 you would have two empty slots.
Alternatively: Use .grep
Another jQuery method is $.grep. See http://api.jquery.com/jquery.grep/
var arr = $.grep([1, 2, 3], function (value) {
return value == 2
});
This is jQuery's implementation of javascript's .filter.
Your array [1, 2, 3] has three elements, and three associated indexes: 0, 1 and 2. In each iteration of your $.each() loop over that array, the index and its value get passed to the function.
So the first call gets 0, 1 passed as its arguments. The second call gets 1, 2 passed as its arguments, then the if statement condition evaluates to true, so your code:
arr[index] = element;
is actually equivalent to
arr[1] = 2;
Since you're inserting an element at index 1, you'll end up with an empty index 0.
You could instead simply use Array.push() to add the element to the array:
arr.push(element);
As already mentioned the problem is you are assigning the value at index 1, so the array will be considered of length 2.
One solution is to use .push() instead of assigning based on index.
Another approach could be is to use Array.filter() and return true if the element matches the conditon
var arr = [1, 2, 3].filter(function(value){
return value == 2
});
Demo: Fiddle
Using $.grep()
var arr = $.grep([1, 2, 3], function (value) {
return value == 2
});
[1, 2, 3]
if (element == 2)
arr[index] = element;
This means you're setting arr[1] to element.
If you want to add it to the arr sequentially (filling it up normally), push it into art
arr.push(element);
Seems like you're looking for Array.filter (MDN).
var elems = ["car", "bike"];
var arr = [1, 2, 3, "car", 5, "bike"].filter(myFilterFunc);
function myFilterFunc(val) {
if (elems.indexOf(val) > -1) return true;
}
Fiddle
I have an array containing 365 objects (date and value), and I would like to reduce this into half to make plotting faster. The reduction has to occur such that I get every other point in the array. So if the first element is for Jan 1, the second element would be for Jan 3 instead of Jan 2. I can iterate through the array and if the number is odd I can add that to the new array or vice versa. But is there a better/faster way to achieve this? I heard crossfilter.js is made for things like this, but wasn't able to figure out how to use it for this case. Any suggestions?
reduce or filter will work for this.
array.reduce(function(memo, item, index) {
index % 2 && memo.push(item);
return memo;
}, [])
array.filter(function(item, index) { return index % 2; })
What you are looking for is Array.filter. filter can be used to filter out the required values from an array, it will result in an array with length lesser or equal to the original array.
The below code returns all the odd elements in the array:
var array = [1,2,3,4,5,6,7,8,9,10]
array.filter(
function (d,indx) {
return indx%2 != 1
}
)
You can use filter function of array
var numbers = [1, 2, 3, 4, 5];
var odds = numbers.filter(function(index, item) {
return index % 2 == 1;
});
I am trying to boost my Javascript understanding, so I've been looking through the Zepto library. I came across this line:
uniq = function(array){
return array.filter(function(item, idx){
return array.indexOf(item) == idx
})
}
What is the purpose of this function? From what I can tell, it is creating a new, unique array of elements, right? But isn't it essentially just cloning the array? If so, wouldn't array.slice() be faster?
Finally, wouldn't it increase performance to change array.indexOf(item) to array.indexOf(item,idx)? Or better yet, just return true? When does array.indexOf(item)==idx not equal true? Is this to prevent duplicate items? But when would that ever actually happen?
it is creating a new, unique array of elements, right?
It just filter your array elements to return unique elements.
demo
But isn't it essentially just cloning the array?
No as I explain above.
If so, wouldn't array.slice() be faster?
Slice doesn't remove duplicates.
Finally, wouldn't it increase performance to change array.indexOf(item) to array.indexOf(item,idx)? Or better yet, just return true?
If you only return true you won't identify if the element is duplicated or not.
demo
When does array.indexOf(item)==idx not equal true?
Example:
I have the following array:
['10', '20', '30', '20', '10']
Iterations:
1: array.IndexOf(10) == 0 ? // yes, so return true
2: array.IndexOf(20) == 1 ? // yes, so return true
3: array.IndexOf(30) == 2 ? // yes, so return true
4: array.IndexOf(20) == 3 ? // no because array.indexOf(20) is 1 , so return false
5: array.IndexOf(10) == 4 ? // no because array.indexOf(10) is 2 , so return false
So, when the element has already been found it gets false because the indexes are not the same.
It seems that this code is eliminating duplicates.
Ahh I see the "difference" we're questioning. You kinda answered it though, in your edit. I think this method returns a new array that contains unique values from the original.
When the indexOf method scans the array, it finds the first occurrence of the currently inspected item. If that occurrence is not the same index as the current index being inspected, the indexOf result will not equal idx. Therefore, it will not return the value because it either wasn't found, or it was found earlier in the array (which means it's a duplicate).
Here's an example:
[10, 30, 10, 100]
When the filter methods goes through the items: 10, 30, 10, then 100, it will perform the indexOf on it.
For 10, indexOf will return 0. And idx is also 0.
For 30, indexOf will return 1. And idx is also 1.
For 10, indexOf will return 0. But idx will be 2.
For 100, indexOf will return 3. And idx is also 3.
Therefore, [10, 30, 100] will be returned, not just a simple clone of the original.
The function (as named) takes unique items in the original array, and returns them in a new array. So if the original array has distinct items, it will just return a clone.
Remember, indexOf returns the first index of a given item. So if the current item appears twice in the array, the filter value will be false.
For example.
var a = [1, 2, 3];
var b = [1, 2, 3, 2];
console.log(uniq(a)); // [1,2,3]
console.log(uniq(b)); // [1,2,3]
As others have said already this gets rid of duplicates in an array. Just added my answer to show why this works. If you log out the values inside the filter function you'll see the pattern:
array.filter(function( item, idx ){
console.log( item, idx, array.indexOf( item ) );
...
...
console.log( uniq( ['a','a','b','b','c','c','c','d'] ) );
/*
a 0 0 *
a 1 0
b 2 2 *
b 3 2
c 4 4 *
c 5 4
c 6 4
d 7 7 *
*/
Check the last column, that's what determines if the item already exists so the comparison array.indexOf(item) == idx checks against the second column, if it's not the same number it is a duplicate. For the item to be unique (*) the index and the index position must match.