split and group array javascript / jquery - javascript

I have
range = [a,3,b,2,c,1,d,2,e,3,f,3]
and need to group a,b,c,d,e,f into 3 same sized groups depending on their values.
Correct result would be:
group1 = [a]
group2 = [b,c]
group3 = [d,e,f]
Update: Pattern -> only group3 can be bigger then 1/3 of total groups. I have so far this:
var range = [3,2,1,2,3,3]
var total = 14;
var group_size = total / 3;
var values = [0];
var groupnr = 0;
range = range.reverse();
while( range.length ) {
var curvalue = range.pop();
if( values[groupnr] + curvalue > group_size && groupnr < 2 ) {
groupnr++;
values[groupnr] = 0;
}
values[groupnr] += curvalue;
}
log(values);

Something like
var range = ['a',3,'b',2,'c',1,'d',2,'e',3,'f',3];
var obj = {};
range.map(function(el, i) {
if (i%2) {
var k = 'group'+el;
obj[k] = obj[k] || [];
obj[k].push(range[i-1]);
}
});
gives you
{
"group1" : ["c"]
"group2" : ["b","d"],
"group3" : ["a","e","f"],
}
FIDDLE
That's about the only thing that would make sense ?

Here's at least one possibility:
var equalSplit = (function() {
var sum = function(list) {return list.reduce(function(a, b) {
return a + b;
}, 0);};
var evens = function(list) {
return list.filter(function(item, index) {return !(index % 2);})
};
var odds = function(list) {
return list.filter(function(item, index) {return !!(index % 2);})
};
var split = function(values, count) {
var mean = sum(values) / values.length;
var groups = [], index = 0, total, groupStart;
for (var i = 0; i < count - 1; i++) {
total = 0; groupStart = index;
while (index < values.length && total < mean) {
total += values[index++];
}
groups.push(values.slice(groupStart, index));
}
groups.push(values.slice(index));
return groups;
};
var reconstituteRanges = function(ranges, splits) {
var groups = {}, ctr = 0, diff;
for (var i = 0; i < splits.length; i++) {
diff = splits[i].length
groups["group" + (i + 1)] =
(evens(ranges.slice(ctr, ctr+=(2 * diff))));
}
return groups;
};
return function(ranges, count) {
var values = odds(ranges);
var splits = split(values, count);
return reconstituteRanges(ranges, splits);
}
}());
var ranges = ['a',3,'b',2,'c',1,'d',2,'e',3,'f',3];
console.log(equalSplit(ranges, 3));
//=> {"group1":["a"],"group2":["b","c"],"group3":["d","e","f"]}
You can see it in action on JSFiddle.
This problem is much simpler than an earlier version, although the code is not that much shorter.
But do you really want to let the last group carry all the weight like this? You originally posted wanting them to be closer to equal. In this case, your weighted totals are [3, 3, 8] for a fairly high variance of 16.67, where [['a'],['b','c','d'],['e','f']] would balance better at [3, 5, 6] for a variance of only 4.67. Is this really your requirement, or was this just a way to write simpler code? (Although this code is not too much shorter than my answer to the previous one, it is substantially simpler.)

Related

Array Processing logic correction

I have an array [1,2,4,5,1,7,8,9,2,3]
and i would like it to generate all subset which sum of values are less than 10
current result [[1,2,4],[5,1],[7],[8],[9],[2,3]]
expected result [[4,5,1],[9,1],[8,2],[3,7],[1,2]]
that is what i did
var a = [1,2,4,5,1,7,8,9,2,3], tempArr = []; tempSum = 0, result = [];
for (var i = 0;i< a.length; i += 1 ) {
tempSum+=a[i];
tempArr.push(a[i]);
if((tempSum+a[i+1])>10) {
result.push(tempArr);
tempSum = 0;
tempArr = [];
} else if (i == a.length-1 && tempArr.length > 0) { // if array is [1,2,3]
result.push(tempArr);
}
}
but it gives me [[1,2,4],[5,1],[7],[8],[9],[2,3]] and it has 6 subset, but i expect to get [[4,5,1],[9,1],[8,2],[3,7],[1,2]] which has 5 subset.
Below logic is in JavaScript :-
var limit = 10;
var arr = [1,2,4,5,1,7,8,9,2,3];
arr.sort();
var ans = new Array ( );
while(arr.length >0){
var ts = arr[arr.length-1];
arr.splice(arr.length-1 , 1);
var ta= new Array ( );
ta.push(ts);
var x = arr.length-1;
while(x>=0){
if(ts + arr[x] <= limit){
ts = ts + arr[x];
ta.push(arr[x]);
arr.splice(x , 1);
}
x= x-1;
}
ans.push(JSON.stringify(ta));
}
alert(ans);
It is Giving Output as required .
[9,1],[8,2],[7,3],[5,4,1],[2]
I have removed duplicates then added maxSum parameter to combine function to generate all subset which have those conditions and then sorted subsets by sum of the values and sliced them.
You could change parameters to fit it for your problem.
var arr = [1,2,4,5,1,7,8,9,2,3]
MAX_SUM = 10,
MIN_SUBSET_LEN = 2,
RESULT_LEN = 5;
//remove duplicates
var uniqeSet = arr.filter(function(value, index){
return this.indexOf(value) == index
},arr);
// a function to get all subset which
// their length are greater than minLength and
// sum of values are little than maxSum
var combine = function(sourceArr, minLength, maxSum) {
var fn = function(n, src, got, all, sum) {
if(sum <= maxSum){
if (n == 0) {
if (got.length > 0) {
all.push({arr:got,sum:sum});
}
return;
}
for (var j = 0; j < src.length; j++) {
var tempSum = sum
fn(n - 1, src.slice(j + 1), got.concat([src[j]]), all, sum + src[j]);
}
}
return;
}
var all = [];
for (var i = minLength; i < sourceArr.length; i++) {
fn(i, sourceArr, [], all, 0);
}
return all;
}
var result = combine(uniqeSet, MIN_SUBSET_LEN, MAX_SUM);
var sortedSliced = result.sort(function(a1, a2){
return a2.sum - a1.sum;
}).slice(0, RESULT_LEN).map(function(m){return m.arr;});
console.log(JSON.stringify(sortedSliced));

How do I get a previous value of a random generated numbers 1 to 10?

I have a random generator from 1 to 10 that produces non repeating values
I am trying to get the previous value.
So if current is 5 and then 8
Previous 8 and next is 9, etc
This is my code:
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 5000);
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1; i < numRandoms; i++) {
randomNumbers.push(i);
}
}
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
i = i - 1; // decrease by one
previous = randomNumbers[i]; // give us back the item of where we are now
randomNumbers.splice(index, 1);
Thank you
This is totally what you're looking for. Hope it helps!.
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 1000);
shuffle = function(o){
for(var j, x, i = o.length; i; j = parseInt(Math.random() * i), x = o[--i], o[i] = o[j], o[j] = x);
return o;
};
var finalArray = shuffle([1, 2, 3, 4,5,6,7,8,9,10]);
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1, l = 11; i < l; i++) { }
}
// var finalArray = shuffle(randomNumbers);
document.write(finalArray + "<br/>");
randomNumbers = finalArray;
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
x = index-1; // decrease by one
current = randomNumbers[randomNumbers.length - 1]; // give us back the item of where we are now
previous = randomNumbers[randomNumbers.length - 2];
if(previous === undefined)
{
previous = "n/a";
}
randomNumbers.pop();
if(randomNumbers.length <= 0){
finalArray = shuffle([1, 2, 3, 4,5,6,7,8,9,10]);
}
document.write("Current >> " + current + " and previous = " +previous + "<br/>")
}
try this:
var randomNumbers = [];
var numRandoms = 11;
var myVar = setInterval(randomUnique1to10, 5000);
var x;
function randomUnique1to10() {
// refill the array if needed
if (!randomNumbers.length) {
for (var i = 1; i < numRandoms; i++) {
randomNumbers.push(i);
}
}
var index = Math.floor(Math.random() * randomNumbers.length);
var val = randomNumbers[index];
if (i === 1) { // i would become 0
i = randomNumbers.length; // so put it at the other end of the array
}
x = index-1; // decrease by one
previous = randomNumbers[x]; // give us back the item of where we are now
var res = randomNumbers.splice(index, 1);
console.log("result: "+res);
console.log("prev : "+previous);
console.log("Rand : "+randomNumbers);
}
NOTE:
this code have, one problem, if res = min(array) then prev will become unidentify
The question lack a bit of clarity. From the question what I understood is,
The values in the array are non repeating
You have a value at variable current and you want to find the previous value of the current which is stored in the array
And I will answer from what I understood. Using indexOf() gives you the index of current element from the array and you just need to subtract 1 from it to get the previous.
var array = [1, 9, 2, 8, 3, 7, 4, 6, 5];
var current = 8;
var currentIndex = array.indexOf(current);
var previous = currentIndex !== 0 ? array[currentIndex-1] : 'N/A';
document.write('Previous Value: ', previous)

show most frequently occuring input value [duplicate]

var store = ['1','2','2','3','4'];
I want to find out that 2 appear the most in the array. How do I go about doing that?
I would do something like:
var store = ['1','2','2','3','4'];
var frequency = {}; // array of frequency.
var max = 0; // holds the max frequency.
var result; // holds the max frequency element.
for(var v in store) {
frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency.
if(frequency[store[v]] > max) { // is this frequency > max so far ?
max = frequency[store[v]]; // update max.
result = store[v]; // update result.
}
}
Solution with emphasis to Array.prototype.forEach and the problem of getting more than one key if the max count is shared among more items.
Edit: Proposal with one loop, only.
var store = ['1', '2', '2', '3', '4', '5', '5'],
distribution = {},
max = 0,
result = [];
store.forEach(function (a) {
distribution[a] = (distribution[a] || 0) + 1;
if (distribution[a] > max) {
max = distribution[a];
result = [a];
return;
}
if (distribution[a] === max) {
result.push(a);
}
});
console.log('max: ' + max);
console.log('key/s with max count: ' + JSON.stringify(result));
console.log(distribution);
arr.sort();
var max=0,result,freq = 0;
for(var i=0; i < arr.length; i++){
if(arr[i]===arr[i+1]){
freq++;
}
else {
freq=0;
}
if(freq>max){
result = arr[i];
max = freq;
}
}
return result;
Make a histogram, find the key for the maximum number in the histogram.
var hist = [];
for (var i = 0; i < store.length; i++) {
var n = store[i];
if (hist[n] === undefined) hist[n] = 0;
else hist[n]++;
}
var best_count = hist[store[0]];
var best = store[0];
for (var i = 0; i < store.length; i++) {
if (hist[store[i]] > best_count) {
best_count = hist[store[i]];
best = store[i];
}
}
alert(best + ' occurs the most at ' + best_count + ' occurrences');
This assumes either there are no ties, or you don't care which is selected.
Another ES6 option. Works with strings or numbers.
function mode(arr) {
const store = {}
arr.forEach((num) => store[num] ? store[num] += 1 : store[num] = 1)
return Object.keys(store).sort((a, b) => store[b] - store[a])[0]
}
If the array is sorted this should work:
function popular(array) {
if (array.length == 0) return [null, 0];
var n = max = 1, maxNum = array[0], pv, cv;
for(var i = 0; i < array.length; i++, pv = array[i-1], cv = array[i]) {
if (pv == cv) {
if (++n >= max) {
max = n; maxNum = cv;
}
} else n = 1;
}
return [maxNum, max];
};
popular([1,2,2,3,4,9,9,9,9,1,1])
[9, 4]
popular([1,2,2,3,4,9,9,9,9,1,1,10,10,10,10,10])
[10, 5]
This version will quit looking when the count exceeds the number of items not yet counted.
It works without sorting the array.
Array.prototype.most= function(){
var L= this.length, freq= [], unique= [],
tem, max= 1, index, count;
while(L>= max){
tem= this[--L];
if(unique.indexOf(tem)== -1){
unique.push(tem);
index= -1, count= 0;
while((index= this.indexOf(tem, index+1))!= -1){
++count;
}
if(count> max){
freq= [tem];
max= count;
}
else if(count== max) freq.push(tem);
}
}
return [freq, max];
}
//test
var A= ["apples","oranges","oranges","oranges","bananas",
"bananas","oranges","bananas"];
alert(A.most()) // [oranges,4]
A.push("bananas");
alert(A.most()) // [bananas,oranges,4]
I solved it this way for finding the most common integer
function mostCommon(arr) {
// finds the first most common integer, doesn't account for 2 equally common integers (a tie)
freq = [];
// set all frequency counts to 0
for(i = 0; i < arr[arr.length-1]; i++) {
freq[i] = 0;
}
// use index in freq to represent the number, and the value at the index represent the frequency count
for(i = 0; i < arr.length; i++) {
freq[arr[i]]++;
}
// find biggest number's index, that's the most frequent integer
mostCommon = freq[0];
for(i = 0; i < freq.length; i++) {
if(freq[i] > mostCommon) {
mostCommon = i;
}
}
return mostCommon;
}
This is my solution.
var max_frequent_elements = function(arr){
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
var max = b[0]
for(var p=1;p<b.length;p++){
if(b[p]>max)max=b[p]
}
var indices = []
for(var q=0;q<a.length;q++){
if(b[q]==max){indices.push(a[q])}
}
return indices;
};
All the solutions above are iterative.
Here's a ES6 functional mutation-less version:
Array.prototype.mostRepresented = function() {
const indexedElements = this.reduce((result, element) => {
return result.map(el => {
return {
value: el.value,
count: el.count + (el.value === element ? 1 : 0),
};
}).concat(result.some(el => el.value === element) ? [] : {value: element, count: 1});
}, []);
return (indexedElements.slice(1).reduce(
(result, indexedElement) => (indexedElement.count > result.count ? indexedElement : result),
indexedElements[0]) || {}).value;
};
It could be optimized in specific situations where performance is the bottleneck, but it has a great advantage of working with any kind of array elements.
The last line could be replaced with:
return (indexedElements.maxBy(el => el.count) || {}).value;
With:
Array.prototype.maxBy = function(fn) {
return this.slice(1).reduce((result, element) => (fn(element) > fn(result) ? element : result), this[0]);
};
for clarity
If the array contains strings try this solution
function GetMaxFrequency (array) {
var store = array;
var frequency = []; // array of frequency.
var result; // holds the max frequency element.
for(var v in store) {
var target = store[v];
var numOccurences = $.grep(store, function (elem) {
return elem === target;
}).length;
frequency.push(numOccurences);
}
maxValue = Math.max.apply(this, frequency);
result = store[$.inArray(maxValue,frequency)];
return result;
}
var store = ['ff','cc','cc','ff','ff','ff','ff','ff','ff','yahya','yahya','cc','yahya'];
alert(GetMaxFrequency(store));
A fairly short solution.
function mostCommon(list) {
var keyCounts = {};
var topCount = 0;
var topKey = {};
list.forEach(function(item, val) {
keyCounts[item] = keyCounts[item] + 1 || 1;
if (keyCounts[item] > topCount) {
topKey = item;
topCount = keyCounts[item];
}
});
return topKey;
}
document.write(mostCommon(['AA', 'AA', 'AB', 'AC']))
This solution returns an array of the most appearing numbers in an array, in case multiple numbers appear at the "max" times.
function mode(numbers) {
var counterObj = {};
var max = 0;
var result = [];
for(let num in numbers) {
counterObj[numbers[num]] = (counterObj[numbers[num]] || 0) + 1;
if(counterObj[numbers[num]] >= max) {
max = counterObj[numbers[num]];
}
}
for (let num in counterObj) {
if(counterObj[num] == max) {
result.push(parseInt(num));
}
}
return result;
}

Decrease the probability of getting random item from array same as previous one

Say, I've got an array like
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
and I wanna get random array item, but later I would like to re-randomize my current item. What is the efficient way to exclude or reduce the chance of getting the same item once again?
Does stuff like this really help:
current != arr[Math.floor(Math.random() * 12)] ? current = arr[Math.floor(Math.random() * 12)] : arr[Math.floor(Math.random() * 12)];
I mean, would it recalculate random array index each time or just link to the same value?
What is a better way?
If you can keep array unsorted: (if not, you can use array which only contains indices of elements in first array)
var array = [ ... ];
var len = array.length;
function getRandomItem(){
if (len <= 0) len = array.length;
var item = Math.floor(Math.random()*len--);
var x = array[item];
array[item] = array[len];
array[len] = x;
return array[len];
}
Idea behind is to exclude already dispatched items by placing them outside of item fetching range. Function getRandomItem() will not return same item twice until all other elements also will be returned.
Following modification will only prevent function to return same element which was returned during previous call, as requested.
var array = [ 3, 1, 4, 5, 9, 2, 6, 8, 7 ];
var len = array.length-1;
function getRandomItem(){
if (len == 0) return array[0];
var item = Math.floor(Math.random()*len);
var x = array[item];
array[item] = array[len];
array[len] = x;
return array[len];
}
document.write("Starting array: " + array + "<br/>");
document.write("Selected value: " + getRandomItem() + "<br/>");
document.write("Resulting array: " + array);
Also see Fisher–Yates shuffle
I think the best solution is to put a while loop to check if the value is similar to the previous one or not.
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
Then you write:
var last_generated_value = null;
var val = Math.random();
val = Math.floor(val * 12);
while(last_generated_val == val)
{
val = Math.random();
val = Math.floor(val * 12);
}
last_generated_value = val;
Though you may put the above code block in a parent loop or a function to generate a concatenated set of values(in your case, number).
There are so many ways to achieve this. Maybe add a weight to each value and consider it in your random number selection? Then when you get it, reduce its weight. For example:
var weights = {};
var max = 12;
function initializeWeights() {
var i;
for (i = 1; i <= max; ++i) {
weights[i] = 100;
}
}
function getPseudoRandom() {
var possible_values = [], i, j;
for (i = 1; i <= max; ++i) {
for (j = 0; j < weights[i]; ++j) {
possible_values.push(i);
}
}
random_index = Math.floor(Math.random() * possible_values.length) + 1;
random = possible_values[random_index];
weights[random] = weights[random] - 10;
return random;
}
initializeWeights()
alert(getPseudoRandom());
Then you just have to figure out what to do when you reach 0. Maybe you can increment all the weights by 100.
Try
var arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12];
var clone = arr.slice();
var res = [];
do {
res.push(clone.splice(Math.random() * clone.length, 1)[0])
} while (clone.length !== 0);
// do stuff with res
document.write(JSON.stringify(res));
document.write(res[Math.floor(Math.random() * res.length)]);
console.log(arr);
perhaps this is ok? It seems to work, but maybe I'm missing some details?
var current = arr[Math.floor(Math.random() * 12)];
var prev = current;
do { current = arr[Math.floor(Math.random() * 12)]; }
while (current == prev);
You could randomly shuffle the array using a version of the Fisher-Yates algorithm and then just iterate through it:
var arr = [1,2,3,4,5,6,7,8,9,10,11,12],
shuffle = function(array) {
for (var i = array.length - 1; i > 0; i--) {
var j = Math.floor(Math.random() * (i + 1));
var temp = array[i];
array[i] = array[j];
array[j] = temp;
}
return array;
},
randomisedArray = shuffle(arr),
nextItem = function(){
return randomisedArray.pop();
};
while(randomisedArray.length>0){
console.log(nextItem());
}
You can do this with a single calculation:
// Just like before...
var arr = [1,2,3,4,5,6,7,8,9,10,11,12];
// Initialize first random index
var currentIndex = Math.floor(Math.random() * arr.length);
// And now...
function Next() {
currentIndex = (Math.floor(Math.random() * (arr.length - 1)) +
1 + currentIndex) % arr.length;
return currentIndex;
}
// Or if you want the next value...
function NextValue() {
return arr[Next()];
}
The idea is that you always randomize how many items to advance, with a maximum of (length - 1), and use modulo to truncate the index into the valid range.

Get the item that appears the most times in an array

var store = ['1','2','2','3','4'];
I want to find out that 2 appear the most in the array. How do I go about doing that?
I would do something like:
var store = ['1','2','2','3','4'];
var frequency = {}; // array of frequency.
var max = 0; // holds the max frequency.
var result; // holds the max frequency element.
for(var v in store) {
frequency[store[v]]=(frequency[store[v]] || 0)+1; // increment frequency.
if(frequency[store[v]] > max) { // is this frequency > max so far ?
max = frequency[store[v]]; // update max.
result = store[v]; // update result.
}
}
Solution with emphasis to Array.prototype.forEach and the problem of getting more than one key if the max count is shared among more items.
Edit: Proposal with one loop, only.
var store = ['1', '2', '2', '3', '4', '5', '5'],
distribution = {},
max = 0,
result = [];
store.forEach(function (a) {
distribution[a] = (distribution[a] || 0) + 1;
if (distribution[a] > max) {
max = distribution[a];
result = [a];
return;
}
if (distribution[a] === max) {
result.push(a);
}
});
console.log('max: ' + max);
console.log('key/s with max count: ' + JSON.stringify(result));
console.log(distribution);
arr.sort();
var max=0,result,freq = 0;
for(var i=0; i < arr.length; i++){
if(arr[i]===arr[i+1]){
freq++;
}
else {
freq=0;
}
if(freq>max){
result = arr[i];
max = freq;
}
}
return result;
Make a histogram, find the key for the maximum number in the histogram.
var hist = [];
for (var i = 0; i < store.length; i++) {
var n = store[i];
if (hist[n] === undefined) hist[n] = 0;
else hist[n]++;
}
var best_count = hist[store[0]];
var best = store[0];
for (var i = 0; i < store.length; i++) {
if (hist[store[i]] > best_count) {
best_count = hist[store[i]];
best = store[i];
}
}
alert(best + ' occurs the most at ' + best_count + ' occurrences');
This assumes either there are no ties, or you don't care which is selected.
Another ES6 option. Works with strings or numbers.
function mode(arr) {
const store = {}
arr.forEach((num) => store[num] ? store[num] += 1 : store[num] = 1)
return Object.keys(store).sort((a, b) => store[b] - store[a])[0]
}
If the array is sorted this should work:
function popular(array) {
if (array.length == 0) return [null, 0];
var n = max = 1, maxNum = array[0], pv, cv;
for(var i = 0; i < array.length; i++, pv = array[i-1], cv = array[i]) {
if (pv == cv) {
if (++n >= max) {
max = n; maxNum = cv;
}
} else n = 1;
}
return [maxNum, max];
};
popular([1,2,2,3,4,9,9,9,9,1,1])
[9, 4]
popular([1,2,2,3,4,9,9,9,9,1,1,10,10,10,10,10])
[10, 5]
This version will quit looking when the count exceeds the number of items not yet counted.
It works without sorting the array.
Array.prototype.most= function(){
var L= this.length, freq= [], unique= [],
tem, max= 1, index, count;
while(L>= max){
tem= this[--L];
if(unique.indexOf(tem)== -1){
unique.push(tem);
index= -1, count= 0;
while((index= this.indexOf(tem, index+1))!= -1){
++count;
}
if(count> max){
freq= [tem];
max= count;
}
else if(count== max) freq.push(tem);
}
}
return [freq, max];
}
//test
var A= ["apples","oranges","oranges","oranges","bananas",
"bananas","oranges","bananas"];
alert(A.most()) // [oranges,4]
A.push("bananas");
alert(A.most()) // [bananas,oranges,4]
I solved it this way for finding the most common integer
function mostCommon(arr) {
// finds the first most common integer, doesn't account for 2 equally common integers (a tie)
freq = [];
// set all frequency counts to 0
for(i = 0; i < arr[arr.length-1]; i++) {
freq[i] = 0;
}
// use index in freq to represent the number, and the value at the index represent the frequency count
for(i = 0; i < arr.length; i++) {
freq[arr[i]]++;
}
// find biggest number's index, that's the most frequent integer
mostCommon = freq[0];
for(i = 0; i < freq.length; i++) {
if(freq[i] > mostCommon) {
mostCommon = i;
}
}
return mostCommon;
}
This is my solution.
var max_frequent_elements = function(arr){
var a = [], b = [], prev;
arr.sort();
for ( var i = 0; i < arr.length; i++ ) {
if ( arr[i] !== prev ) {
a.push(arr[i]);
b.push(1);
} else {
b[b.length-1]++;
}
prev = arr[i];
}
var max = b[0]
for(var p=1;p<b.length;p++){
if(b[p]>max)max=b[p]
}
var indices = []
for(var q=0;q<a.length;q++){
if(b[q]==max){indices.push(a[q])}
}
return indices;
};
All the solutions above are iterative.
Here's a ES6 functional mutation-less version:
Array.prototype.mostRepresented = function() {
const indexedElements = this.reduce((result, element) => {
return result.map(el => {
return {
value: el.value,
count: el.count + (el.value === element ? 1 : 0),
};
}).concat(result.some(el => el.value === element) ? [] : {value: element, count: 1});
}, []);
return (indexedElements.slice(1).reduce(
(result, indexedElement) => (indexedElement.count > result.count ? indexedElement : result),
indexedElements[0]) || {}).value;
};
It could be optimized in specific situations where performance is the bottleneck, but it has a great advantage of working with any kind of array elements.
The last line could be replaced with:
return (indexedElements.maxBy(el => el.count) || {}).value;
With:
Array.prototype.maxBy = function(fn) {
return this.slice(1).reduce((result, element) => (fn(element) > fn(result) ? element : result), this[0]);
};
for clarity
If the array contains strings try this solution
function GetMaxFrequency (array) {
var store = array;
var frequency = []; // array of frequency.
var result; // holds the max frequency element.
for(var v in store) {
var target = store[v];
var numOccurences = $.grep(store, function (elem) {
return elem === target;
}).length;
frequency.push(numOccurences);
}
maxValue = Math.max.apply(this, frequency);
result = store[$.inArray(maxValue,frequency)];
return result;
}
var store = ['ff','cc','cc','ff','ff','ff','ff','ff','ff','yahya','yahya','cc','yahya'];
alert(GetMaxFrequency(store));
A fairly short solution.
function mostCommon(list) {
var keyCounts = {};
var topCount = 0;
var topKey = {};
list.forEach(function(item, val) {
keyCounts[item] = keyCounts[item] + 1 || 1;
if (keyCounts[item] > topCount) {
topKey = item;
topCount = keyCounts[item];
}
});
return topKey;
}
document.write(mostCommon(['AA', 'AA', 'AB', 'AC']))
This solution returns an array of the most appearing numbers in an array, in case multiple numbers appear at the "max" times.
function mode(numbers) {
var counterObj = {};
var max = 0;
var result = [];
for(let num in numbers) {
counterObj[numbers[num]] = (counterObj[numbers[num]] || 0) + 1;
if(counterObj[numbers[num]] >= max) {
max = counterObj[numbers[num]];
}
}
for (let num in counterObj) {
if(counterObj[num] == max) {
result.push(parseInt(num));
}
}
return result;
}

Categories