Important edit : I can't use filter - the purpose is pedagogic.
I have an array in which I would want to count the number of its elements that verify a boolean, using only map and reduce.
Count of the array's size
I already wrote something that counts the array's size (ie. : the number of all of its elements), using reduce :
const array_numbers = [12, 15, 1, 1]; // Size : 4
console.log(
array_numbers.reduce((acc) => {
return acc + 1;
}, 0)
);
Count of the array's elements checking a boolean condition
Now I would want to count only the elements that verify a boolean condition. Thus, I must use map before reduce and the elements of the map's returned array will be only the good elements.
So I wrote this code but it doesn't work... Indeed, I put null when I encounter a not-good element (and null is counted as en element unfortunately).
NB : here, the boolean condition is "is the element even ? (%2 == 0)".
const array_numbers = [12, 15, 1, 1]; // Size : 4
console.log(
array_numbers.map((current_value) => {
if(current_value % 2 == 0) {
return current_value;
}
return null;
}).reduce((acc) => {
return acc + 1;
}, 0)
);
Array#filter the array and check the length:
const array_numbers = [12, 15, 1, 1];
const result = array_numbers.filter((n) => n % 2 === 0).length;
console.log(result);
Or count using Array#reduce:
const array_numbers = [12, 15, 1, 1, 4];
const result = array_numbers.reduce((r, n) => n % 2 ? r : r + 1, 0);
console.log(result);
Or if you must, you can use Array#map with Array#reduce:
const array_numbers = [12, 15, 1, 1, 4];
const result = array_numbers
.map((n) => n % 2 === 0 ? 1 : 0) // map to 1 or 0 according to the condition
.reduce((r, n) => r + n); // sum everything
console.log(result);
You can use Array.prototype.filter to filter the even numbers - and you don't need the reduce() function - you can use length of the array returned by the filter() function.
Or you can use reduce() method alone like below:
See demos below:
const array_numbers = [12, 15, 1, 1]; // Size : 4
// using filter
console.log(
array_numbers.filter((current_value) => {
return current_value % 2 == 0;
}).length
);
// using reduce
console.log(
array_numbers.reduce((prev, curr) => {
return curr % 2 == 0 ? prev + 1 : prev;
}, 0)
);
Since per your comment you must use reduce for some reason:
arr.reduce((acc, n) => { n % 2 ? acc + n : acc }, 0);
The map is unecessary.
As Jared Smith mentioned, you don't need to use map for this task.
Array.reduce() gets the current element as a second argument in the callback function which you can use to check if it satisfies your given condition.
So, again assuming that you must use either map and/or reduce:
const myArray = [1,2,3,4,5,6];
const condition = function(a) {
// let's say
return a %2 == 0;
}
let result = myArray.reduce((acc, val) => {
return condition(val) ? acc + 1 : acc
}, 0);
console.log(result);
Related
Is there a nice ES6 way of splitting an array into an array of arrays with each element in source array going into the next target array and repeating across all of the source array?
For example
source = [1,2,3,4,5,6,7,8,9,10,11,12,13]
if target arrays were 2 I would like to get output
output = [
[1,3,5,7,9,11,13],
[2,4,6,8,10,12]
]
if target arrays were 3 I would like to get output
output = [
[1,4,7,10,13],
[2,5,8,11],
[3,6,9,12]
]
Using reduce, it can be done. Here's the solution for a size of target array:
[1,2,3,4,5,6,7,8,9,10,11,12,13].reduce(function (acc, curr, idx) {
acc[idx % size] ? acc[idx % size].push(curr) : acc[idx % size] = [curr];
return acc
}, []);
You can do something like this
Get the divisor and remainder
create a array of length n, with values `divisor + 1 ( for first remainder number of elements ) OR 0 ( we use this to equally distribute the extra elements to the initial elements )
Loop over the array we created above and slice the array and add to final array
let source = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13]
let divideInParts = (arr, number) => {
let divisor = Math.floor(arr.length / number)
let remainder = arr.length % number
let tempArr = Array.from({length: number}, (_,i)=> divisor +( remainder-- > 0 ))
let start = 0
let final = tempArr.map((v,i)=>{
let val = i === 0 ? arr.slice(0, v) : arr.slice(start, start + v)
start += v
return val
})
return final
}
console.log(divideInParts(source, 2))
console.log(divideInParts(source, 3))
console.log(divideInParts(source, 13))
console.log(divideInParts(source, 10))
I want to return an array of indices of an array which has positive elements using pure functions in JS. EX:
pos([1,-4,0,5,2])
>>[0,2,3,4]
So, I tried:
arr.map(function (ele){
return arr.findIndex(ele => ele > 0);
})
But my output is :[1,1,1,1]
Can someone tell me what is wrong? I believe that my map function is correct but something is wrong with findIndex(). (Please don't tell me the code as it is a question of my assignment. Only need hints.)
map() isn't quite right because you won't have corresponding output for every element in the original array. reduce() is probably what you want in this case:
function pos(arr){
return arr.reduce((ret_arr, number, index) => {
if (number >= 0) ret_arr.push(index)
return ret_arr
}, [])
}
console.log(pos([1,-4,0,5,2]))
You could first map the index, if the value is positive or -1 and then filter the array for existing indices.
Array#map returns a new array with the index of the element or -1 if the element is smaller than zero.
Array#filter returns all values which are not -1. The short adding just one returns a truthy value which is a possible index.
function pos(array) {
return array // [1, -4, 0, 5, 2]
.map((v, i) => v < 0 ? -1 : i) // [0, -1, 2, 3, 4]
.filter(i => i + 1); // [0, 2, 3, 4]
}
console.log(pos([1, -4, 0, 5, 2]));
Your callback for mapping
function pos(arr) {
return arr.map(function (ele) {
return arr.findIndex(ele => ele > 0);
});
}
console.log(pos([1, -4, 0, 5, 2]));
takes no element, because the first ele variable is never used later. Then you return always the index of the first element of arr, which is 1. This value is greater as zero and the callback for find returns true abd find hands over the actual index.
Don't use findIndex. Basically you are looking for
function pos(arr) {
var res = [];
for (const [index, el] of arr.entries())
if (el > 0)
res.push(index)
return res;
}
If you want to do this using the higher-order array methods, you could do
function pos(arr) {
return arr.map((ele, index) => [ele, index])
.filter(([ele]) => ele > 0)
.map(([_, origIndex]) => origIndex);
}
#NinaScholz has a good approach as well, though I'd write it as
function pos(arr) {
return arr.map((ele, index) => ele > 0 ? index : null)
.filter(index => index !== null);
}
Try this:
[1,-4,0,5,2].reduce((acc,value,i) => value >= 0 ? [...acc,i] : acc,[]);
In any case where you're ding both filtering and ?something-else? reduce is always the best option.
For basic algorithms like this try returning a new array containing the previous values via spread.
const possitive = [];
const negative = [];
const array = [-1, -2, 0, 4, 1, 3, 2];
// Separate negative from possitive values
array.map(number =>
number >= 0 ? possitive.push(number) : negative.push(number)
);
// Sort accessing order
possitive.sort((a, b) => a - b);
negative.sort((a, b) => a - b);
// Join both arrays
const completed = possitive.concat(negative);
// Console log completed array
console.log(completed);
//Result
[0, 1, 2, 3, 4, -2, -1];
I am able to calculate the sum of last n elements of an array using for loop as below. How can I achieve the same using Arr.reduceRight?
x = [1,2,3,4,5];
y = 0
for(let i=x.length; i>x.length-3; i--) {
console.log(x[i-1]);
y +=x[i-1];
}
console.log(y);
Here is the codepen link: https://codepen.io/anon/pen/rrNxZB?editors=0011
You can first slice the array, then reduce the resulting array. No need for reduceRight as the sum operation is commutative.
x = [1, 2, 3, 4, 5];
n = 4;
y = x.slice(-n).reduce((acc, val) => acc + val);
console.log(y);
In a reduceRight (or reduce), there is 2 arguments
A callback
The initial value (optional, in that case last/first will be init value, and it will start from second-last/second for reduceRight/reduce accordingly)
Now the callback having 4 arguments,
The accumulator (what we returned (each) last time, init or last/first value for the first time)
Each entry (from second last/second depending on init value passed or not)
Current index
The Entire Collection (This is mostly useful when you are in a continuous chain)
All you have to do is, (assuming you have to add last N number)
IF (Collection length - Current index) <= N Then Add Current Value with sum and return
ELSE Return Current Sum ignoring current value
So you can do,
array.reduceRight((sum, each, idx, a) => (a.length - idx) > N ? sum : sum + each , 0)
Now, you can remove the ternary and do (sum + either 0 or Each Number) conditionally
so sum + ((array.length - idx) <= N && each)
If the condition (array.length - idx) <= N is false it will return false and it will not go to the and operator otherwise it will return value of each, so it will add false (0) or each value conditionally
array.reduceRight((sum, each, idx, a) => sum + ((a.length - idx) <= N && each), 0)
let arr = [100, 200, 300, 400, 500, 600, 700, 800, 900, 1000],
N = 4,
sum = arr.reduceRight((s, e, i, a) => s + ((a.length - i) <= N && e), 0);
console.log(`Sum of last ${N} values: :`, sum);
You could use a closure over a count c and check this values and decrement and take the value with a logical AND &&.
This proposal uses Array#reduceRight, as wanted.
var array = [1, 2, 3, 4, 5],
sum = array.reduceRight((c => (s, v) => s + (c && c-- && v))(3), 0)
console.log(sum);
x = [1,2,3,4,5];
n = 3; // How many numbers to take
console.log(x.slice(-n).reduceRight((prev, curr) => prev + curr, 0))
reduceRight takes two arguments: a callback and the initial value. We initialise it to 0 as we are counting.
curr in my example will be 3, then 4 then 5. prev will be 0, then 3, then 7.
See: Array.ReduceRight
var n = 4;
var x = [1, 2, 3, 4, 5];
var y = x.reduceRight(function(accumulator, currentValue) {
if (n > 0) { // If n = 0, stop calculating the sum.
accumulator += currentValue;
}
n--; // Reducing n value for every loop.
return accumulator;
}, 0);
console.log(y);
Pretty simple :
var x = [1,2,3,4,5];
var n = 2;
var y = x.reduceRight((accumulator, currentValue, index) =>{
if(index < x.length-n) return accumulator;
return accumulator + currentValue;
}, 0);
console.log(y);
https://developer.mozilla.org/de/docs/Web/JavaScript/Reference/Global_Objects/Array/ReduceRight
has a good example on almost exactly that.
const elementCountToLeaveOut = 3;
console.log([1,2,3,4,5].reduceRight((acc, val, idx) => idx >= elementCountToLeaveOut ? acc + val : acc))
You can try this logic:
Create a variable of final index(fIndex) where the loop should end.
Then you can loop using reduceRight and check if passed index is smaller then fIndex
If yes, return last calculated value
If no, return sum value.
function sumRight(arr, n) {
var fIndex = arr.length - n;
return arr.reduceRight(function(sum, num, index) {
return index < fIndex ? sum : sum + num
}, 0)
}
var x = [1,2,3,4,5]
console.log(sumRight(x, 3))
Something like this one
lastN=(x,n)=>(m=x.length-n,x.reduceRight((a,v,i)=>{return a+=i>=m?v:0;},0))
As part of a bigger function, I'm trying to simply run a check to see whether the values in an array are 'increasing' - e.g.:
var a = [1,2,3,4,5] // is increasing
var a = [1,4,6,7,36] // is increasing
var a = [1,6,3,6,5] // not increasing
It's increasing if the previous value a[previous] is less than a[next]. For some reason, the problem is it doesn't return -1 when it's not increasing. And, as I'm learning JavaScript, my code seems way more complex than it should be.
My Questions:
1. why does it not return -1 when a cannot increase?
2. why is my code seemingly so complex for such a simple test? am I missing something? (that is, if you think it's overcomplex, which often my code is)
What would be a better way of writing such a function? Should I put the 'test if already increased' part inside a separate function? If someone could also give hints about writing better, simpler, readable, drier code, that would be much appreciated :)
var a = [1,2,3,4,5]
var canIncrease = 0; // boolean
// test if already increased
for(i=0;i<a.length;i++) {
if((a[i] < a[i+1] && i !== a.length-1)||(a[i] > a[i-1] && i==a.length-1)) {
console.log('index ' + i + ' cannot increase');
} else {
console.log('index ' + i + ' can increase');
canIncrease = 1;
}
}
if (!canIncrease) {
console.log('array a cannot increase');
return -1;
} else {
console.log('would continue');
// continue with main function...
}
You can use every() and return true if the element is the last element OR smaller than the next element.
function func(arr) {
return arr.every((o, i, a) => (i + 1) === a.length || o < a[i + 1] );
}
console.log(func([1, 2, 3, 4, 5]));
console.log(func([1, 4, 6, 7, 36]));
console.log(func([1, 6, 3, 6, 5]));
Doc: every()
To answer your last question, this can be simplified to the following:
var a = [1,2,3,4,5]
var b = [1,4,6,7,36]
var c = [1,6,3,6,5]
function isIncreasing(arr) {
return arr.every((n, i) => i === 0 || n[i - 1] < n);
}
isIncreasing(a); //true
isIncreasing(b); //true
isIncreasing(c); //false
You can use the .reduce method to achieve the desired result:
The .reduce method applies a function against an accumulator and each element in the array (from left to right) to reduce it to a single value.
on every element compare the current element curr with the saved one acc. If the current is greater and not false save it in acc for the next element. Else set acc to false.
At the end, if the array is in ascending acc will be an integer (the last element in the array, i.e. the maximum). Else acc will be false.
adding !! before the statement ensures the integers are converted to bools.
So the statement will look like:
!!a.reduce((acc, curr) => (acc && (curr >= acc)) ? curr : false)
ES6 syntax:
() => {} or () => are shorthand syntax to define functions (arrow functions)
condition ? expr1 : expr2 is a ternary operator, it's equivalent to if(condition) { expr1 } else { expr2 }
Here are some tests:
const isAscOrder = (a) => !!a.reduce((acc, curr) => (acc && (curr >= acc)) ? curr : false);
console.log(
isAscOrder([2, 2, 3, 4, 5]) // is increasing
);
console.log(
isAscOrder([1, 6, 3, 6, 5]) // is not increasing
);
console.log(
isAscOrder([2, 1, 2, 3, 4, 5]) // is not increasing
);
I've just noticed the previous function didn't work if the array contained a 0: for example: [0, 2, 2, 3, 4, 5]. The reason being that 0 is false. In order to solve this, we can use NaN instead of false:
!isNaN(a.reduce((acc, curr) => (!isNaN(acc) && (curr >= acc)) ? curr : NaN))
const isAscOrder = (a) => !isNaN(a.reduce((acc, curr) => (!isNaN(acc) && (curr >= acc)) ? curr : NaN));
console.log(
isAscOrder([0, 2, 2, 3, 4, 5]) // is increasing
);
console.log(
isAscOrder([1, 6, 3, 6, 5]) // is not increasing
);
console.log(
isAscOrder([2, 1, 2, 3, 4, 5]) // is not increasing
);
I want to sort only odd numbers without moving even numbers. For example, when I write :
sortArray([5, 3, 2, 8, 1, 4])
The expected result is :
[1, 3, 2, 8, 5, 4]
I am new to JavaScript and I came across a challenge on the Internet that has me perplexed. I normally wouldn't post asking for a solution on the Internet, BUT I have tried for hours and I would like to learn this concept in JavaScript.
The challenge states :
You have an array of numbers.
Your task is to sort ascending odd numbers but even numbers must be on their places.
Zero isn't an odd number and you don't need to move it. If you have an empty array, you need to return it.
Here is my code so far, please take it easy on me I am in the beginning stages of programming.
function sortArray(array) {
let oddNums = [];
for(let i = 0; i < array.length; i++) {
if(array[i] % 2 !== 0) {
oddNums.push(array[i]);
}
}
oddNums = oddNums.sort((a,b)=> a-b);
array.concat(oddNums);
array = array.sort((a,b) => a-b);
return array;
}
You could take a helper array for the odd indices and another for the odd numbers, sort them and apply them back on the previously stored indices of the original array.
var array = [5, 3, 2, 8, 1, 4],
indices = [];
array
.filter((v, i) => v % 2 && indices.push(i))
.sort((a, b) => a - b)
.forEach((v, i) => array[indices[i]] = v);
console.log(array);
Here's a solution using mostly the built-in array methods. Get a list of just the odds, sort it, then map through the original, replacing each item with the first sorted odd if the item is odd, or itself if even:
const array = [5, 3, 2, 8, 1, 4] // to: [1, 3, 2, 8, 5, 4]
function sortOddsOnly(arr) {
const odds = arr
.filter(x => x%2)
.sort((a, b) => a - b);
return arr
.map(x => x%2 ? odds.shift() : x);
}
console.log(sortOddsOnly(array));
I have a solution like this.
Build a sorted odd number array 1st, and then fill the rest of even numbers in order:
const arr = [5, 3, 2, 8, 1, 4];
const odd = arr.filter(i => i%2 !== 0).sort();
let i = 0,
result = [];
arr.forEach(e => {
if (e%2 === 0) {
result.push(e)
} else {
result.push(odd[i]);
i++;
}
});
console.log(result);
just do:
arr.sort((a, b) => a%2 && b%2 ? a - b : 0)
If that works depends on the sort algorithm your browser uses.
A browserindependent version:
for(const [i1, v1] of arr.entries())
for(const [i2, v2] of arr.entries())
if( v1%2 && v2%2 && (i1 < i2) === (v1 > v2))
([arr[i1], arr[i2]] = [v2, v1]);
One of the possible solutions is this. What I have done is created new array odd(array with odd position in original array using Array.prototype.filter) and then sort that array using Array.prototype.sort. Then using Array.prototype.map change value of all odd element of original array with odd array.
x1=[5, 3, 2, 8, 1, 4];
function sortArray(array) {
var odd = array.filter((x,i) => (i+1) % 2 ).sort((a,b) => a > b); //sort odd position and store that in new array
return array.map((x,i) => (i+1) % 2 ? odd.shift() : x ); //if i is odd then replace it with element from
//odd array otherwise keep the element as it is
}
console.log(sortArray(x1));
Here is a possible solution using a slightly customized selection sort :
var xs = [5, 3, 2, 8, 1, 4];
console.log(sortOddsOnly(xs));
function sortOddsOnly (xs) {
var n = xs.length;
for (var i = 0; i < n - 1; i++) {
if (xs[i] % 2 === 1) {
for (var j = i + 1; j < n; j++) {
if (xs[j] % 2 === 1) {
if (xs[i] > xs[j]) {
var min = xs[j];
xs[j] = xs[i];
xs[i] = min;
}
}
}
}
}
return xs;
}
The first two if guarantee that we swap only odd numbers (x % 2 === 1 means "x is odd").
def sort_array(source_array):
b = sorted([n for n in source_array if n % 2 != 0])
c = -1
d = []
for i in source_array:
c = c+1
if i % 2 != 0 :
d.append(c)
for x in range (len(d)):
z = d[x]
source_array[z] = b[x]
return source_array