Can two loops be merged into one? - javascript

I'm using the following function to add specific numbers into an array that I later want to be assigned to a variable. For this I'm using two for loops, but I feel like there is a more succinct way to do it. I tried merging the two loops in one without getting an error, but the output is not the same.
Working Example:
function fill () {
var array = [];
for (var index = 0; index < arguments.length; index++) {
for (var number = arguments[index][0]; number <= arguments[index][1]; number++)
array.push(number);
}
return array;
};
/* Use */
var keys = fill([1, 10], [32, 34]);
/* Output */
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34]
Merged Example:
function fill () {
var array = [];
for (var index = 0, number = arguments[index][0];
index < arguments.length && number <= arguments[index][1];
index++ && number++) {
array.push(number);
}
return array;
};
/* Use */
var keys = fill([1, 10], [32, 34]);
/* Output */
[1, 1]
Is it possible to actually merge the two loops into one? If not, is there a way to write the foregoing function in less code?

Your code in the first example is fine. There is no real "clean" way to remove the nested loops.
You could iterate over them with forEach, but then you'd still have nested loops, even if one of them is disguised as a function call:
function fill () {
var array = [];
Array.prototype.slice.apply(arguments) // Make an array out of arguments.
.forEach(function(arg){
for (var number = arg[0]; number <= arg[1]; number++){
array.push(number);
}
});
return array;
};
console.log(fill([1, 10], [32, 34]));
And you'd have to use Array.prototype.slice.apply to convert arguments to an actual array. (which is ugly)
So, basically, nested loops aren't necessarily "evil". Your first example is as good as it gets.

JavaScript is a functional language. For the sake of modern coding purposes a functional approach is best for the coder's benefit.
var fillArray = (...args) => args.reduce((res,arg) => res.concat(Array(...Array(arg[1]-arg[0]+1)).map((e,i) => i + arg[0])),[]),
filled = fillArray([1, 10], [32, 34]);
console.log(filled);
OK what happens here.. It's very simple. We do the job by fillArray function. fillArray function takes indefinite number of arguments. So we collect them all in an array called args by utilizing the ES6 rest operator ....
var fillArray = (...args)
Now that we have our source arrays in the args array we will apply a reduce operation to this array with an initial value of an empty array (res). What we will do is.. as per each source (arg) array we will create a new array and then we will concatenate this to the res array. Ok we receive [1,10] as source which means we need an array of length arg[1]-arg[0]+1 right. So comes
Array(...Array(arg[1]-arg[0]+1))
we could also do like Array(arg[1]-arg[0]+1).fill() same thing. We now have an array filled with "undefinite" in the needed length. Then comes map. This is really very simple as we apply to this undefinites array like
.map((e,i) => i + arg[0]))
which means each item will be the current index + offset which is the arg[0]
Then we concatenate this array to our results array and pass to the next source array. So you see it is very straight forward and maintainable.

You might not be able to escape the two loops, but that shouldn't necessarily be a goal either. The loop themselves aren't really harmful – it's only if you're iterating over the same data multiple times that you might want to reconsider your code
Consider this entirely different approach
const range = (x , y) =>
x > y
? []
: [ x, ...range (x + 1, y) ]
const concat = (xs, ys) =>
xs .concat (ys);
const flatMap = (f, xs) =>
xs .reduce ((acc, x) => concat (acc, f (x)), [])
const apply = f => xs =>
f (...xs)
const fill = (...ranges) =>
flatMap (apply (range), ranges);
console.log
(fill ( [1,10]
, [32,34]
, [40,49]
, [100,100]
)
)
So yes, #Redu is on the right track with "JavaScript is a functional language", but I think his/her answer falls short of delivering a well-composed functional answer.
The answer above shows how functions with individualized concerns can be easy to read, easy to write, and easy to combine to achieve complex computations.

In ES6, you could use the rest operator and build a new array, based on the items.
function fill(...p) {
return p.reduce((r, a) => r.concat(Array.apply(null, { length: a[1] - a[0] + 1 }).map(() => a[0]++)), []);
};
var keys = fill([1, 10], [32, 34]);
console.log(keys);

Similar to another answer, but a little more complete:
const arrays = [[1,10],[32,34],[9,12]]
const range = (a,b) => a >= b ? [] :
[...Array(b-a).keys()].map(i => i+a)
const result = arrays.reduce( (a,c) =>
a.concat( range(c[0], c[1]+1) ), [] )
// => [ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 32, 33, 34, 9, 10, 11, 12 ]
If you prefer a more traditional range function, then:
const arrays = [[1,10],[32,34],[9,12]]
function range(a,b) {
var arr = []
for (let i = a; i < b; i++)
arr.push(i)
return arr
}
const result = arrays.reduce( function(a,c) {
return a.concat( range(c[0], c[1]+1) )
}, [] )

After almost 2 years and some great answers that were posted to this thread proposing interesting alternatives, I found a way to merge the two loops into one, but it ain't pretty!
Code:
function fill () {
var
ar = [],
imax = arguments.length,
/* The functions that calculate the bounds of j. */
jmin = i => arguments[i][0],
jmax = i => arguments[i][1] + 1;
for (
let i = 0, j = jmin(i);
i < imax && j < jmax(i);
/* If j reaches max increment i and if i is less than max set j to min. */
ar.push(j++), (j == jmax(i)) && (i++, (i < imax) && (j = jmin(i)))
);
return ar;
};
/* Use */
var keys = fill([1, 10], [32, 34], [76, 79]);
console.log.apply(console, keys);

Related

write a function that would loop through an array and get the two(or more) indexes that satisfy a condition together

Consider that we have an array of length n being filled with random numbers, i want to write a function that would loop through an array and get the two(or more) indexes that satisfy a condition together.
For instance:
const arr = [12, 10, 2, 3, 17, 42, 56, 38]
write a function to get the two indexes such that if you multiplied their elements, it would bring out the largest answer. (56*42 would be the answer in this scenario)
I understand that in this case, you could just multiply the largest array element with the second largest, however a question of this nature could be much more complex and there could be much more conditions to solve for and the elements in the array could also be unknown. i am merely after the principle of the answer. If you could provide a solution to this question whilst briefly explaining how you came across your answer, it would be much appreciated.
When you know, that your accumulation function is steady, then you can simply order the array and return the indices of the two largest elements.
If you do not know, that the accumulation function is steady, then you can pairwise calculate the result of such function and, if the result is larger than your current cumulated value, remember the indices of the elements, which generated this value.
A function like this one can solve the problem with all accumulation functions passed as parameter:
const findHighestIndices = (values, accumlationFunction) => {
let currentMaximum = -Infinity;
let indices = [];
for (let i = 0; i < values.length; i++) {
for (let j = 0; j < values.length; j++) {
if (i === j) continue; // we only want to compare DIFFERENT elements
const cummulation = accumlationFunction(values[i], values[j]);
if (cummulation <= currentMaximum) continue;
currentMaximum = cummulation;
indices = [i, j];
}
}
return indices;
};
const arr = [12, 10, 2, 3, 17, 42, 56, 38];
console.log(findHighestIndices(arr, (a, b) => a * b));
When there is no order of parameters of the accumulation function, my implementation is highly optimizable, as you won't need to run the elements for both, i and j.
Not a native javascript developer, hope this can help.
I would loop over the list the number of indices expected to statisfy the condition and test the condition. Since, you don't want to use the same index two times, pass in this case.
const arr = [12, 10, 2, 3, 17, 42, 56, 38]
var max = -Infinity;
var max_i = 0
var max_j = 0
for(var i=0; i< arr.length; i++) {
for(var j=0; j< i+1; j++){
if(i==j){
//pass
}
var mul = arr[i]*arr[j];
if (mul > max){max = mul;max_i = i; max_j = j}
}}
The resulting indices are max_i and max_j.

Handle 2 objects in map() function in JS

I have a tricky question, at least for me, today. First of all I want to present you the code example which I want to acomplish:
var numbers= [1,2,3,4];
var newNumbers = values.map((v1, v2) => {
return v1+v2;
});
console.log(newNumbers ); //[wanted output: 3, 7]
The idea behind that is that I can map over an array but not with one item like usualy, this time I want to do this with pairs. Also I want to handle this little problem incase I have an odd amount of numbers:
var numbers= [1,2,3,4,5];
var newNumbers = values.map((v1, v2) => {
return v1*v2; //when v1 is 5 and v2 out of range, treat v2 as 0
});
console.log(newNumbers ); //[wanted output: 2, 12, 0]
Is it possible to handle this in JS or does anybody have an idea how I could map over an array in this special way?
.map is only for when the input array and output array items are one-to-one. Since you're looking to go from 4 items to 2, you'll need a different method.
A plain for loop works.
const numbers = [1, 2, 3, 4];
const output = [];
for (let i = 0; i < numbers.length; i += 2) {
output.push(numbers[i] + (numbers[i + 1] || 0));
}
console.log(output);
The || 0 at the end there will work for when the last number isn't paired with another.
This is not extremely practical but a possible way to solve it using ES6 iterators:
function sumPairs(arr) {
const result = [];
const iterator = arr.values(); //1
for (const x of iterator) { //2
const [y = 0] = iterator; //3 and 4
result.push(x+y);
}
return result;
}
console.log(sumPairs([1, 2, 3, 4]));
console.log(sumPairs([1, 2, 3, 4, 5]));
Array#values() gets an iterator over the values of an array.
for..of will go through the iterator. That is how it works by spec - even if you use for (const x of arr) internally the for..of will get the default iterator of arr which is the same as .values().
Using array destructuring also works on iterators by spec. The name is actually a bit misleading - it looks like an array because of the [ and ] and you can use it on arrays like const [a, b, c] = someArray.
However destructuring assignment using square brackets will always draw from an iterator. If it is already given an iterator, it is the same as calling iterator.next().value. In the case of const [y] = iterator it would draw a second value after x. So, each iteration of the loop advances through two of the items of the array.
The destructuring assignment allows using some syntax sugar - in this case specifying default values. With [y = 0] the second item drawn from the array will have a default if it happens to be undefined. The for..of will stop once there are no more items the iterator can produce.
if the array had an even number of items, then getting a y will be the last item, so the next iteration the loop ends:
if the array has an odd number of items, then x will be the last item of the iterator and y will get a value from an already exhausted iterator and thus the last iteration will just use the default for y.
function pairs(arr) {
const iterator = arr.values();
for (const x of iterator) {
const [y = 0] = iterator;
console.log(x, y);
}
}
pairs([1, 2]);
console.log("-----");
pairs([1, 2, 3]);
See also: Iteration protocols on MDN
The above approach can be generalised with a generator function that accepts any iterable and returns pairs of items until it is exhausted.
function* pairs(iterable) {
const iterator = iterable[Symbol.iterator]();
for (const x of iterator) {
const [y] = iterator;
yield [x, y];
}
}
The sumPairs function then just needs to consume those pairs by summing them and then adding them to an array:
function* pairs(iterable) {
const iterator = iterable[Symbol.iterator]();
for (const x of iterator) {
const [y] = iterator;
yield [x, y];
}
}
function sumPairs(arr) {
const result = [];
for (const [x, y = 0] of pairs(arr)) {
result.push(x+y);
}
return result;
}
console.log(sumPairs([1, 2, 3, 4]));
console.log(sumPairs([1, 2, 3, 4, 5]));
With a generator in place, the sumPairs can furrther be condensed to just an Array.from(), since it accepts any iterable as a first parameter and a mapping function for a second parameter.
const sumPairs = arr =>
Array.from(pairs(arr), ([x, y = 0]) => x+y);
function* pairs(iterable) {
const iterator = iterable[Symbol.iterator]();
for (const x of iterator) {
const [y] = iterator;
yield [x, y];
}
}
const sumPairs = arr =>
Array.from(pairs(arr), ([x, y = 0]) => x+y);
console.log(sumPairs([1, 2, 3, 4]));
console.log(sumPairs([1, 2, 3, 4, 5]));

Order an unordered array of numbers from 1-8, so that the end and starting integers are alternated eg [8,1,7,2,6,3,5,4,]

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 :)

counting number of occurrences in an array [duplicate]

I have an array:
[1, 2, 3, 5, 2, 8, 9, 2]
I would like to know how many 2s are in the array.
What is the most elegant way to do it in JavaScript without looping with for loop?
[this answer is a bit dated: read the edits, in the notion of 'equal' in javascript is ambiguous]
Say hello to your friends: map and filter and reduce and forEach and every etc.
(I only occasionally write for-loops in javascript, because of block-level scoping is missing, so you have to use a function as the body of the loop anyway if you need to capture or clone your iteration index or value. For-loops are more efficient generally, but sometimes you need a closure.)
The most readable way:
[....].filter(x => x==2).length
(We could have written .filter(function(x){return x==2}).length instead)
The following is more space-efficient (O(1) rather than O(N)), but I'm not sure how much of a benefit/penalty you might pay in terms of time (not more than a constant factor since you visit each element exactly once):
[....].reduce((total,x) => (x==2 ? total+1 : total), 0)
or as a commenter kindly pointed out:
[....].reduce((total,x) => total+(x==2), 0)
(If you need to optimize this particular piece of code, a for loop might be faster on some browsers... you can test things on jsperf.com.)
You can then be elegant and turn it into a prototype function:
[1, 2, 3, 5, 2, 8, 9, 2].count(2)
Like this:
Object.defineProperties(Array.prototype, {
count: {
value: function(value) {
return this.filter(x => x==value).length;
}
}
});
You can also stick the regular old for-loop technique (see other answers) inside the above property definition (again, that would likely be much faster).
2017 edit:
Whoops, this answer has gotten more popular than the correct answer. Actually, just use the accepted answer. While this answer may be cute, the js compilers probably don't (or can't due to spec) optimize such cases. So you should really write a simple for loop:
Object.defineProperties(Array.prototype, {
count: {
value: function(query) {
/*
Counts number of occurrences of query in array, an integer >= 0
Uses the javascript == notion of equality.
*/
var count = 0;
for(let i=0; i<this.length; i++)
if (this[i]==query)
count++;
return count;
}
}
});
You could define a version .countStrictEq(...) which used the === notion of equality. The notion of equality may be important to what you're doing! (for example [1,10,3,'10'].count(10)==2, because numbers like '4'==4 in javascript... hence calling it .countEq or .countNonstrict stresses it uses the == operator.)
Caveat:
Defining a common name on the prototype should be done with care. It is fine if you control your code, but bad if everyone wants to declare their own [].count function, especially if they behave differently. You may ask yourself "but .count(query) surely sounds quite perfect and canonical"... but consider perhaps you could do something like [].count(x=> someExpr of x). In that case you define functions like countIn(query, container) (under myModuleName.countIn), or something, or [].myModuleName_count().
Also consider using your own multiset data structure (e.g. like python's 'collections.Counter') to avoid having to do the counting in the first place. This works for exact matches of the form [].filter(x=> x==???).length (worst case O(N) down to O(1)), and modified will speed up queries of the form [].filter(filterFunction).length (roughly by a factor of #total/#duplicates).
class Multiset extends Map {
constructor(...args) {
super(...args);
}
add(elem) {
if (!this.has(elem))
this.set(elem, 1);
else
this.set(elem, this.get(elem)+1);
}
remove(elem) {
var count = this.has(elem) ? this.get(elem) : 0;
if (count>1) {
this.set(elem, count-1);
} else if (count==1) {
this.delete(elem);
} else if (count==0)
throw `tried to remove element ${elem} of type ${typeof elem} from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)`;
// alternatively do nothing {}
}
}
Demo:
> counts = new Multiset([['a',1],['b',3]])
Map(2) {"a" => 1, "b" => 3}
> counts.add('c')
> counts
Map(3) {"a" => 1, "b" => 3, "c" => 1}
> counts.remove('a')
> counts
Map(2) {"b" => 3, "c" => 1}
> counts.remove('a')
Uncaught tried to remove element a of type string from Multiset, but does not exist in Multiset (count is 0 and cannot go negative)
sidenote: Though, if you still wanted the functional-programming way (or a throwaway one-liner without overriding Array.prototype), you could write it more tersely nowadays as [...].filter(x => x==2).length. If you care about performance, note that while this is asymptotically the same performance as the for-loop (O(N) time), it may require O(N) extra memory (instead of O(1) memory) because it will almost certainly generate an intermediate array and then count the elements of that intermediate array.
Modern JavaScript:
Note that you should always use triple equals === when doing comparison in JavaScript (JS). The triple equals make sure, that JS comparison behaves like double equals == in other languages (there is one exception, see below). The following solution shows how to solve this the functional way, which will ensure that you will never have out of bounds error:
// Let has local scope
let array = [1, 2, 3, 5, 2, 8, 9, 2]
// Functional filter with an Arrow function
// Filter all elements equal to 2 and return the length (count)
array.filter(x => x === 2).length // -> 3
The following anonymous Arrow function (lambda function) in JavaScript:
(x) => {
const k = 2
return k * x
}
may be simplified to this concise form for a single input:
x => 2 * x
where the return is implied.
Always use triple equals: === for comparison in JS, with the exception of when checking for nullability: if (something == null) {} as it includes a check for undefined, if you only use double equals as in this case.
Very simple:
var count = 0;
for(var i = 0; i < array.length; ++i){
if(array[i] == 2)
count++;
}
2017:
If someone is still interested in the question, my solution is the following:
const arrayToCount = [1, 2, 3, 5, 2, 8, 9, 2];
const result = arrayToCount.filter(i => i === 2).length;
console.log('number of the found elements: ' + result);
Here is an ES2017+ way to get the counts for all array items in O(N):
const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const counts = {};
arr.forEach((el) => {
counts[el] = counts[el] ? (counts[el] + 1) : 1;
});
You can also optionally sort the output:
const countsSorted = Object.entries(counts).sort(([_, a], [__, b]) => a - b);
console.log(countsSorted) for your example array:
[
[ '2', 3 ],
[ '1', 1 ],
[ '3', 1 ],
[ '5', 1 ],
[ '8', 1 ],
[ '9', 1 ]
]
If you are using lodash or underscore the _.countBy method will provide an object of aggregate totals keyed by each value in the array. You can turn this into a one-liner if you only need to count one value:
_.countBy(['foo', 'foo', 'bar'])['foo']; // 2
This also works fine on arrays of numbers. The one-liner for your example would be:
_.countBy([1, 2, 3, 5, 2, 8, 9, 2])[2]; // 3
Weirdest way I can think of doing this is:
(a.length-(' '+a.join(' ')+' ').split(' '+n+' ').join(' ').match(/ /g).length)+1
Where:
a is the array
n is the number to count in the array
My suggestion, use a while or for loop ;-)
Not using a loop usually means handing the process over to some method that does use a loop.
Here is a way our loop hating coder can satisfy his loathing, at a price:
var a=[1, 2, 3, 5, 2, 8, 9, 2];
alert(String(a).replace(/[^2]+/g,'').length);
/* returned value: (Number)
3
*/
You can also repeatedly call indexOf, if it is available as an array method, and move the search pointer each time.
This does not create a new array, and the loop is faster than a forEach or filter.
It could make a difference if you have a million members to look at.
function countItems(arr, what){
var count= 0, i;
while((i= arr.indexOf(what, i))!= -1){
++count;
++i;
}
return count
}
countItems(a,2)
/* returned value: (Number)
3
*/
I'm a begin fan of js array's reduce function.
const myArray =[1, 2, 3, 5, 2, 8, 9, 2];
const count = myArray.reduce((count, num) => num === 2 ? count + 1 : count, 0)
In fact if you really want to get fancy you can create a count function on the Array prototype. Then you can reuse it.
Array.prototype.count = function(filterMethod) {
return this.reduce((count, item) => filterMethod(item)? count + 1 : count, 0);
}
Then do
const myArray =[1, 2, 3, 5, 2, 8, 9, 2]
const count = myArray.count(x => x==2)
Most of the posted solutions using array functions such as filter are incomplete because they aren't parameterized.
Here goes a solution with which the element to count can be set at run time.
function elementsCount(elementToFind, total, number){
return total += number==elementToFind;
}
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(elementsCount.bind(this, elementToFind), 0);
The advantage of this approach is that could easily change the function to count for instance the number of elements greater than X.
You may also declare the reduce function inline
var ar = [1, 2, 3, 5, 2, 8, 9, 2];
var elementToFind=2;
var result = ar.reduce(function (elementToFind, total, number){
return total += number==elementToFind;
}.bind(this, elementToFind), 0);
Really, why would you need map or filter for this?
reduce was "born" for these kind of operations:
[1, 2, 3, 5, 2, 8, 9, 2].reduce( (count,2)=>count+(item==val), 0);
that's it! (if item==val in each iteration, then 1 will be added to the accumulator count, as true will resolve to 1).
As a function:
function countInArray(arr, val) {
return arr.reduce((count,item)=>count+(item==val),0)
}
Or, go ahead and extend your arrays:
Array.prototype.count = function(val) {
return this.reduce((count,item)=>count+(item==val),0)
}
It is better to wrap it into function:
let countNumber = (array,specificNumber) => {
return array.filter(n => n == specificNumber).length
}
countNumber([1,2,3,4,5],3) // returns 1
I use this:
function countElement(array, element) {
let tot = 0;
for(var el of array) {
if(el == element) {
tot++;
}
}
return tot;
}
var arr = ["a", "b", "a", "c", "d", "a", "e", "f", "a"];
console.log(countElement(arr, "a")); // 4
var arrayCount = [1,2,3,2,5,6,2,8];
var co = 0;
function findElement(){
arrayCount.find(function(value, index) {
if(value == 2)
co++;
});
console.log( 'found' + ' ' + co + ' element with value 2');
}
I would do something like that:
var arrayCount = [1,2,3,4,5,6,7,8];
function countarr(){
var dd = 0;
arrayCount.forEach( function(s){
dd++;
});
console.log(dd);
}
I believe what you are looking for is functional approach
const arr = ['a', 'a', 'b', 'g', 'a', 'e'];
const count = arr.filter(elem => elem === 'a').length;
console.log(count); // Prints 3
elem === 'a' is the condition, replace it with your own.
Array.prototype.count = function (v) {
var c = 0;
for (let i = 0; i < this.length; i++) {
if(this[i] === v){
c++;
}
}
return c;
}
var arr = [1, 2, 3, 5, 2, 8, 9, 2];
console.log(arr.count(2)); //3
Solution by recursion
function count(arr, value) {
if (arr.length === 1) {
return arr[0] === value ? 1 : 0;
} else {
return (arr.shift() === value ? 1 : 0) + count(arr, value);
}
}
count([1,2,2,3,4,5,2], 2); // 3
Create a new method for Array class in core level file and use it all over your project.
// say in app.js
Array.prototype.occurrence = function(val) {
return this.filter(e => e === val).length;
}
Use this anywhere in your project -
[1, 2, 4, 5, 2, 7, 2, 9].occurrence(2);
// above line returns 3
Here is a one liner in javascript.
Use map. Find the matching values (v === 2) in the array, returning an array of ones and zeros.
Use Reduce. Add all the values of the array for the total number found.
[1, 2, 3, 5, 2, 8, 9, 2]
.map(function(v) {
return v === 2 ? 1 : 0;
})
.reduce((a, b) => a + b, 0);
The result is 3.
Depending on how you want to run it:
const reduced = (array, val) => { // self explanatory
return array.filter((element) => element === val).length;
}
console.log(reduced([1, 2, 3, 5, 2, 8, 9, 2], 2));
// 3
const reducer = (array) => { // array to set > set.forEach > map.set
const count = new Map();
const values = new Set(array);
values.forEach((element)=> {
count.set(element, array.filter((arrayElement) => arrayElement === element).length);
});
return count;
}
console.log(reducer([1, 2, 3, 5, 2, 8, 9, 2]));
// Map(6) {1 => 1, 2 => 3, 3 => 1, 5 => 1, 8 => 1, …}
You can use built-in function Array.filter()
array.filter(x => x === element).length;
var arr = [1, 2, 3, 5, 2, 8, 9, 2];
// Count how many 2 there are in arr
var count = arr.filter(x => x === 2).length;
console.log(count);
One-liner function
const countBy = (a,f)=>a.reduce((p,v,i,x)=>p+!!f(v,i,x), 0)
countBy([1,2,3,4,5], v=>v%2===0) // 2
There are many ways to find out. I think the easiest way is to use the array filter method which is introduced in es6.
function itemCount(array, item) {
return array.filter(element => element === item).length
}
const myArray = [1,3,5,7,1,2,3,4,5,1,9,0,1]
const items = itemCount(myArray, 1)
console.log(items)
Something a little more generic and modern (in 2022):
import {pipe, count} from 'iter-ops';
const arr = [1, 2, 3, 5, 2, 8, 9, 2];
const n = pipe(arr, count(a => a === 2)).first; //=> 3
What's good about this:
It counts without creating a new array, so it is memory-efficient
It works the same for any Iterable and AsyncIterable
Another approach using RegExp
const list = [1, 2, 3, 5, 2, 8, 9, 2]
const d = 2;
const counter = (`${list.join()},`.match(new RegExp(`${d}\\,`, 'g')) || []).length
console.log(counter)
The Steps follows as below
Join the string using a comma Remember to append ',' after joining so as not to have incorrect values when value to be matched is at the end of the array
Match the number of occurrence of a combination between the digit and comma
Get length of matched items
I believe you can use the new Set array method of JavaScript to have unique values.
Example:
var arr = [1, 2, 3, 5, 2, 8, 9, 2]
var set = new Set(arr);
console.log(set);
// 1,2,3,5,8,9 . We get unique values as output.
You can use length property in JavaScript array:
var myarray = [];
var count = myarray.length;//return 0
myarray = [1,2];
count = myarray.length;//return 2

ramda equivalent for rotate

Given a rotate function like the one below, which rotates the array a set number of slots.
Is there an equivalent Ramda.js function or composition that will do this rotation?
var test = [1,2,3,4,5,6,7,8,9];
function rotate(arr, count) {
arr = arr.slice();
while (count < 0) {
count += arr.length;
}
count %= arr.length;
if (count) {
arr.splice.apply(arr, [0, 0].concat([].slice.call(arr.splice(arr.length - count, count))));
}
return arr;
}
example
rotate(test, 2) // -> [8, 9, 1, 2, 3, 4, 5, 6, 7]
Here's a point-free one liner which takes the count first and the data second, consistent with ramda's composable style:
const rotate = pipe(splitAt, reverse, flatten);
Of course you can always flip(rotate) to get a data first version.
UPDATE
Sorry, I read too fast and assumed the normal, left-wise direction for the rotation (eg, as it is in ruby). Here's a variation of the idea that does what your original does:
const rotate = pipe(useWith(splitAt, [negate, identity]), reverse, flatten);
This is similar to #donnut's answer, but includes modulo arithmetic to handle counts which exceed the length of the given list:
var rotate2 = function(xs, count) {
var n = -(count % xs.length);
return R.concat(R.slice(n, Infinity, xs),
R.slice(0, n, xs));
};
Here's a mutation-free equivalent which doesn't use Ramda at all:
var rotate3 = function(xs, count) {
var n = -(count % xs.length);
return xs.slice(n).concat(xs.slice(0, n));
};
Both solutions are significantly more declarative than the solution in the original post.
You could try:
function reverse(arr, count) {
return R.concat(R.slice(arr.length-count, arr.length, arr), R.slice(0, arr.length-count, arr));
}
See http://bit.ly/1G90ny8

Categories