Find highest amount of repeating value in an array using JavaScript - javascript

I have an array with repeating values:
[0, 1, 6, 0, 1, 0]
What is an efficient way to return the highest amount that a specific value repeats?
In the example array I would want the script to return 3 because the number 0 repeats the most often and it repeats 3 times.
I'm already using jQuery and Underscore.

If you use lodash...
_.max(_.countBy(a,_.identity))
More about lodash: http://lodash.com/

This is similar to the basic approach, but utilizes underscore's reduce and max functions. If you had a really really really large array, I hope it's clear how you could parallelize this with a map phase before the reduce.
var arr = [1,0,2,3,4,0,3,0];
var counts = _.reduce(arr, function(counts, val) {
if (counts[val]) {
counts[val]++;
} else {
counts[val] = 1;
}
return counts;
}, {});
return _.max(counts);

Yay, this is like a google interview question lol. I would recommend looping through your array once and maintaining an associative array of each element as you encounter it in the while incrementing a counter.
For example:
http://jsfiddle.net/btKjX/
var a = [0, 0 , 2, 2, 3, 3, 3, 3];
var counts = {};
for(var i = 0, il = a.length; i < il; i++){
var num = a[i];
if(typeof counts[num] === 'undefined'){
counts[num] = 0;
}
counts[num]++;
}
var max = -1;
for(var c in counts){
if(counts[c] > max){
max = counts[c];
}
}
console.log(max);

a hacky way might be to sort it, split it on every value change and then look at the length of each string, but let's try something more reasonable:
var nums = [0, 1, 6, 0, 1, 0]
var occurence = {}
$.each(nums, function(a, num_id) {
if (occurence[num_id] != null) {
occurence[num_id]++;
} else {
occurence[num_id] = 1;
}
});
occurence would then have the number of occurences of every value in nums, with the number itself being the key.

Related

Split array into arrays of numbers where the sum is equal to a specific target

I need to create a function that take as parameter an array and a target. It should return an array of arrays where the sum of these numbers equals to the target
sumPairs(array, target) {
}
For example:
sumPairs([1, 2, 3, 4, 5], 7) // output : [[2, 5], [3, 4]]
I know I have to use map(), and probably reduce(), set(), or filter() maybe (I read their documentation in MDN but still cant find out). I tried some ways but I can't get it.
If you guys could help me to find out how to dynamically create arrays and push them into a new array..
I read there some solutions (Split array into arrays of matching values) but I hate to just use created functions without knowing what they really do or how they work.
Some very basic code for achieving it, Just run all over combinations and conditionally add the items you want.
function sumPairs(array, target) {
var res = [];
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array.length; j++){
if(i!=j && array[i]+array[j]==target &&
res.filter((x)=> x[0] == array[j] && x[1] == array[i]).length == 0 )
res.push([array[i], array[j]]);
}
}
return res;
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
Option 2 - see this answer for more options (like using reduce)
function sumPairs(array, target) {
return array.flatMap(
(v, i) => array.slice(i+1).filter(w => (v!=w && v+w==target)).map(w=> [w,v])
);
}
var result = sumPairs([1, 2, 3, 4, 5], 7);
console.log(result);
"The exercise says that it sould be arrays of pairs that sum the
target value so I think only 2 items"
If you need a pair that matches a sum and you pick any number from the list, you are left with
the following equation to solve num + x = sum where we want to find x. E.g. if you picked 7 and the target sum is 10 then you know you are looking for a 3.
Therefore, we can first construct a counting map of the numbers available in our list linear (O(n)) time and then search for matches in linear time as well rather than brute forcing with a quadratic algorithm.
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
return nums.reduce((pairs, num) => {
countByNum[num]--;
const target = sum - num;
if (countByNum[target] > 0) {
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[num]++;
}
return pairs;
}, []);
}
function countGroupByNum(nums) {
return nums.reduce((acc, n) => (acc[n] = (acc[n] || 0) + 1, acc), {});
}
Here's another implementation with more standard paradigms (e.g. no reduce):
const nums = [1, 2, 3, 4, 5];
console.log(findSumPairs(nums, 7));
function findSumPairs(nums, sum) {
const countByNum = countGroupByNum(nums);
const pairs = [];
for (const num of nums) {
const target = sum - num; //Calculate the target to make the sum
countByNum[num]--; //Make sure we dont pick the same num instance
if (countByNum[target] > 0) { //If we found the target
countByNum[target]--;
pairs.push([num, target]);
} else {
countByNum[target]++; //Didin't find a match, return the deducted num
}
}
return pairs;
}
function countGroupByNum(nums) {
const countByNum = {};
for (const num of nums) {
countByNum[num] = (countByNum[num] || 0) + 1;
}
return countByNum;
}
You can also sort your array and find all the pairs with given sum by using two pointer method. Place the first pointer to the start of the array and the second pointer to the end.
if the sum of the values at the two places is :
More than target: Decrement your second pointer by 1
Less than target: Increment your first pointer by 1
Equal to target: This is one possible answer, push them to your answer array and increment your first pointer by 1 and decrement your second pointer by 1.
This is more performant solution with complexity O(n*log(n))

For Loop that calculates sum of squred numbers in array

I am working on a challenge and in need of some help:
Write a for loop that calculates sum of squares of items in an array of numbers. Example: For array [ 1, 2, 3, 4 ] it calculates the sum of squares as 30 (i.e. 1 + 4 + 9 + 16). I have a fiddle set up if anyone wants to have a closer look. Thanks for your help!
https://jsfiddle.net/jamie_shearman/2drt56e3/23/
var aFewNumbers = [ 1, 2, 3, 7 ];
var squareOfAFewNumbers = 0;
for( var i = 0; i <= aFewNumbers; i++ ) {
squareOfAFewNumbers = squareOfAFewNumbers * aFewNumbers[i] ;
}
console.log( squareOfAFewNumbers );
Your math is wrong. As an obvious issue, the variable starts at 0 and then is multiplied by each array element; 0 times anything is 0, so it will always remain 0 no matter what the values are. Not to mention your loop isn't looking at the length of the array as a stopping condition, which it should be, since you want to iterate from the beginning to the end of the array.
You need to iterate through to the array's length, square each array element, and add that square to the variable:
for( var i = 0; i < aFewNumbers.length; i++ ) {
squareOfAFewNumbers += aFewNumbers[i] * aFewNumbers[i];
}
If you can use ES6, you can even use higher-order array functions to simplify this more:
var squareOfAFewNumbers = aFewNumbers.reduce((result, entry) => result + entry * entry, 0);
There are multiple approaches you can take for reaching the desired result, but as you've mentioned that you must write a for loop; therefore, I sorted the answers by having that in mind.
Using the for loop
let numbers = [1, 2, 3, 7],
sum = 0;
for(let i = 0; i < numbers.length; i++) {
sum += Math.pow(numbers[i], 2)
}
// Sum is now 63
Using forEach method of the array object
let numbers = [1, 2, 3, 7],
sum = 0;
numbers.forEach(number => sum += Math.pow(number, 2))
// Sum is now 63
Oneliner
let sum = [1, 2, 3, 7].reduce((a, c) => a + Math.pow(c, 2))
The reduce method uses an accumulator to store temporary results, the accumulator is passed to the callback as the first argument and the second argument is the element's value, you can read more about the reduce method here.
You can use JavaScript pow() Method to create the square and sum it to the sumSquareOfAFewNumbers.
var aFewNumbers = [ 1, 2, 3, 7 ];
var sumSquareOfAFewNumbers = 0;
aFewNumbers.forEach(function(element) {
sumSquareOfAFewNumbers += Math.pow(element, 2);
});
console.log(sumSquareOfAFewNumbers)

How do I prevent this last "broken condition" from being pushed to array

I am dynamically slicing an array, and I can get the functionality I want by simply removing the last element with arr.pop() but I want to know exactly why my while loop is adding this to my array when it breaks my conditional.
slices(num){
let arr = [this.digits.slice(0, num)]
let i = 0
if (this.digits.length < num){
throw new Error('Slice size is too big.')
} else {
while (arr[i].length === num){
i++
arr.push(this.digits.slice(i, num + i))
}
// arr.pop() - removed for testing
return arr
}
}
Here is an example. Let's say we want to slice this array:
this.digits = [ 3, 1, 0, 0, 1 ]
Ideally, our output will look like this:
[3, 1, 0], [1, 0, 0], [0, 0, 1]]
With my current code and without using arr.pop(), my algorithim will consistently sneak in an extra slice iteration that has less length than what my conditional is asking for (in this case, num == 3)
This will be my output:
[[3, 1, 0], [1, 0, 0], [0, 0, 1], [0, 1]]
I know there are many ways to do this, but for this, I would like to maintain the integrity of my code, so a solution that uses my implementation would be great :D
EDIT: I get why the last element is being added. Since the element before fulfills the conditional (it's length is equal to num), it moves on to the next iteration but how I do handle it eloquently without using .pop()
EDIT: Thanks all for the answers! They all seem like they would work, but Peter B's implementation was so very clean, especially given that he changed just a few lines for me and it worked like a charm. Thanks again!
You are checking the wrong condition in the while. It is better to calculate how many sub-arrays you are going to add inside the while (in addition to the one that you start with), and count up to that number, like this:
var digits = [3, 1, 0, 0, 1];
function slices(num) {
let arr = [this.digits.slice(0, num)]
let i = 0
if (this.digits.length < num) {
throw new Error('Slice size is too big.')
} else {
var sliceCutoff = this.digits.length - num;
while (i < sliceCutoff) {
i++
arr.push(this.digits.slice(i, num + i))
}
return arr
}
}
console.log(slices(3));
You need to check if the leftover items are enough to get an array with the wanted length. That means, you need a single loop with a continuing check for the actual ster index, wanted size and the length.
An approach by checking the last array after splicing is unnecessary, because it generates an avoidable overhead.
function slice(array, n) {
var result = [],
start = 0;
while (start + n <= array.length) {
result.push(array.slice(start, start++ + n));
}
return result;
}
var array = [3, 1, 0, 0, 1];
console.log(slice(array, 3));
Description
I believe that you're looking for something along the lines of this? As you can see, I've also removed some redundant code, i.e. using a while loop in this scenario and the else clause.
I've also just declared digits as a parameter for this demo, I believe that you'd have the initiative to be able to change this to your application(s) requirement(s) without much/any assistance.
function slices(digits, num) {
const arr = [];
if (digits.length < num)
throw new Error('Slice size is too big.')
for (let i = 0; i != num; i++)
arr.push(digits.slice(i, num + i));
return arr;
}
var d = [3, 1, 0, 0, 1]; // Only here for the demo.
console.log(slices(d, 3));
You're really close. I think my proposed solution here keeps the general idea of yours. The problem you're hitting is that checking arr[i].length being equal to num means this is only checking the last item you added to the array, not the next one. Instead, check the item you're about to add.
this.digits = [ 3, 1, 0, 0, 1 ];
function slices(num) {
let arr = []
let i = 0
if (this.digits.length < num) {
throw new Error('Slice size is too big.')
} else {
while (this.digits.slice(i, num + i).length === num){
arr.push(this.digits.slice(i, num + i))
i++
}
// arr.pop() - removed for testing
return arr
}
}
console.log(slices(3));

Compare 2 or more sorted arrays javascript

I'm trying to handroll a solution for poker. I've gotten all the logic to determine the best 5 card hand. I'm having issues comparing multiple arrays for which have higher elements in the event of ties(with regard to hand type).
Say we have some potential winners for a flush.
var low_flush = [2, 3, 4, 5, 7]
var medium_flush = [3, 4, 5, 6, 8]
var high_flush = [2, 3, 4, 5, 9]
I want to build a function that i pass any number of arrays to and it returns the "highest poker hand" or an array of hands in the event of an actual tie:
function bestHand(hands){
//
return high_hand
}
Everything I've read thus far is how to compare just two arrays, and usually with that, it only sees if there are equal to each other. If it helps heres my source code
My first thoughts are to iterate over the hands. And for each iteration, iterate over the hands again for comparison. Just thinking about this pseudocode is making my head hurt and was thinking their might be a more elegant solution for this and/or library(not a poker library though)
I am using underscore in other parts of the codebase so feel free to use it in answer as well!
You can use reduce() first to count the sum of each array
var total3 = high_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
after that push each one to an array with total of array and the name of the winner
allhands.push({total: total1 , name: "low_flush"});
then compare them with compare function and sort you array
function compare(a,b) {
if (a.total < b.total)
return -1;
else if (a.total > b.total)
return 1;
else
return 0;
}
allhands.sort(compare);
Working example here:
var low_flush = [2, 3, 4, 5, 7];
var medium_flush = [2, 3, 4, 5, 8];
var high_flush = [2, 3, 4, 5, 9];
var allhands = [];
var total3 = high_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total3 , name: "high_flush"});
var total1 = low_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total1 , name: "low_flush"});
var total2 = medium_flush.reduce(function(previousValue, currentValue) {
return previousValue + currentValue;
}, 0);
allhands.push({total: total2 , name: "medium_flush"});
function compare(a,b) {
if (a.total < b.total)
return -1;
else if (a.total > b.total)
return 1;
else
return 0;
}
allhands.sort(compare);
console.log("The winner is "+allhands[allhands.length - 1].name +"With total:"+ allhands[allhands.length - 1].total );
<script src="http://gh-canon.github.io/stack-snippet-console/console.min.js"></script>
This may seem silly. But this seems to work for me.
var hands = [ [2, 3, 4, 5, 7], [2, 3, 5, 9, 8], [2, 3, 4, 5, 9] ];
var values = [];
function bestHand(hands){
hands.forEach(function(arr, index) {
var temp = arr.slice();
values[index] = parseInt(temp.sort().reverse().join(''));
});
var max = Math.max.apply(Math, values);
return hands[values.indexOf(max)];
}
bestHand(hands);
Obviously you need to pass an array of hand objects to something like this.
function getBest(...hands){
return hands.sort((p,c) => p.weight() <= c.weight() ? -1:1)[hands.length-1]
}
when it comes to finding out the weight of a hand object in tie conditions it could be first determined by the hands color (spades beats all) and then by sum of the card values for clubs like 2,3,4,5,6,7,8,9,10,11(j),12(q),13(k),14(a). The sum of them all is 104 so for diamonds card values can be (104+2), (104+3), (104+4) etc.. for hearts you offset values by 208 and for spades by 312.
hand.prototype.weight = function(){
return this.reduce((p,c) => p.value + c.value)
}
Of course this will only handle the tie conditions. It can not tell a flush from a flush royale.
Take a look at array's reduce function here.
Example:
var result = hands.reduce(function(prevHand, currentHand) {
return compareHands(prevHand,currentHand) ? prevHand : currentHand;
});
This answers the question about comparing multiples arrays, but keep in mind that it will reduce it to one value, this may not be the perfect solution since you have to consider draws. In that case your result should be an array, and in the comparison push into the array or reinitialize and add it to the array.
function bestHands(DescOrderedHands){
bestHand = DescOrderedHands[0]
bestHandScore = parseInt(_.map(bestHand, function(num){return num.toString}).join(""))
_.each(DescOrderedHands, function(hand){
stringHand = _.map(hand, function(num){return num.toString}).join("")
if (parseInt(stringHand) > bestHandScore){
bestHand = hand
}
}
return bestHand
}
First, You have to be sure that all arrays in your your function have the same length, then you have to sort each array, and finally you have to compare each value of each array.
You should have something like this
function bestHand(hands){
var best_hand = null;
for(var i = 0; i < hands.length; ++i){
hands[i] = hands[i].sort();
if(i > 0){
for(var j = 0; j < hands[i].length; ++j){
if(best_hand[j] < hands[i][j]){
best_hand = hands[i];
break;
}
else if(best_hand[j] > hands[i][j]){
break;
}
}
}
else{
best_hand = hands[i];
}
}
return best_hand;
}
Be sure you pass arrays with the same length in argument

breaking an array into subsets

I am trying to get this function to split an array into subsets. each subset is to have numbers that are equal to the previous or within 1 from the previous number.
The example I have below should return two subsets but it returns {0, 1, 2, 3} instead. Any idea on what I am doing wrong? Also, is there a better way to dynamically create an array for each new subset? Thanks
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function(a, b){return a-b});
for(var i = 0; i<myarr.length; i++){
var iplus = i+1;
if(i === i || i === iplus){
newArr= [];
newArr.push(i);
}else if (i !== i || i !== iplus){
arr2 =[];
arr2.push(i);
}
}
}
What you are trying to do is usually called "partitioning". The generic version of the problem is to partition an array into sub-arrays using some "rule", or predicate, or condition, which specifies which partition a particular element is supposed to go into, or specifies that it should go into a new partition.
The pseudo code for doing this would be:
To partition an array:
Initialize the resulting array
For each element in the array
If that element starts a new chunk
Create a new empty chunk in the resulting array
Add the element to the most recent chunk
Return the result
This can be expressed in JS quite straightforwardly as
function partition(array, fn) {
return array.reduce((result, elt, i, a) => {
if (!i || !fn(elt, i, a)) result.push([]);
result[result.length - 1].push(elt);
return result;
}, []);
}
Now we need to write the function saying when a new partition should start:
// Is the element within one of the previous element?
function close(e, i, a) {
return Math.abs(e - a[i-1]) > 1;
}
We can now partition the array with
partition([[4, 13, 2, 3], close)
This should work.
function max_tickets() {
var arr = [4, 13, 2, 3];
var myarr = arr.sort(function (a, b) { return a - b });
arrSubsets = [];
arr1 = [];
for (var i = 0; i < myarr.length; i++) {
if (myarr[i - 1] === undefined) {
arr1.push(myarr[i]);
continue;
}
if (myarr[i] - myarr[i - 1] <= 1) {
arr1.push(myarr[i]);
}
else {
arrSubsets.push(arr1);
arr1 = [];
arr1.push(myarr[i]);
}
}
if (arr1.length > 0)
arrSubsets.push(arr1);
}
max_tickets();
Based on your questions:
Any idea on what I am doing wrong?.
Inside of your loop you are using i as if it is the value of the array, but the loop goes from 0 to the value of myarr.length in your particular case 4, so that makes the value of i to be 0, 1, 2, 3.
As you can see you are using the values of the index to compare, instead of using the values of the array in order to use the values of the array you must specify the arrayname[index], in your case myarr[i] that will give you the values: 4, 13, 2, 3.
Also, is there a better way to dynamically create an array for each new subset?
Yes you can create an array inside of another array dynamically inside of a loop:
var b = [];
for(var i = 0; i < 10; i++){
b.push(['I am' + i, i]);
}
As you can see in the previous example I'm creating an array inside of the b array so once the loop finishes the b array will have 10 arrays inside of it with 2 elements each.

Categories

Resources