Using JavaScript, I'm trying to find a way to find the longest occurrence of the same number (in this case, 1) in an array.
For instance, here's a sample array:
[2,5,3,1,1,1,3,7,9,6,4,1,1,1,1,1,4,7,2,3,1,1,4,3]
I'd like to write a function that would return "5", since the number 1 occurs 5 times in a row. (It also occurs 3 and 2 times in a row, but I'm after the longest occurrence).
So far, I have written:
function streak(arr) {
var i,
temp,
streak,
length = arr.length;
for(i=0; i<length; i++) {
if (arr[i] === 1) {
streak += 1;
} else {
temp = streak;
break;
}
}
}
I know I need some way of knowing where I left off if I find an occurrence, but I'm feeling kind of stuck.
Any pointers?
I've modified your function slightly. You need to store the highest streak as a separate variable from the current streak, and overwrite that where necessary in your loop - finally returning that variable at the end of your function.
function streak(arr) {
var i,
temp,
streak,
length = arr.length,
highestStreak = 0;
for(i = 0; i < length; i++) {
// check the value of the current entry against the last
if(temp != '' && temp == arr[i]) {
// it's a match
streak++;
} else {
// it's not a match, start streak from 1
streak = 1;
}
// set current letter for next time
temp = arr[i];
// set the master streak var
if(streak > highestStreak) {
highestStreak = streak;
}
}
return highestStreak;
}
var array = [2,5,3,1,1,1,3,7,9,6,4,1,1,1,1,1,4,7,2,3,1,1,4,3];
console.log(streak(array)); // 5
And if you want to also track what the value of the highest streak was, define another variable at the start of your function, save the value of it when you save the highest streak, and return it as an array:
// set the master streak var
if(streak > highestStreak) {
highestStreakValue = temp;
highestStreak = streak;
}
}
return [highestStreak, highestStreakValue];
var array = [2,5,3,1,1,1,3,7,9,6,4,'a','a','a','a','a',4,7,2,3,1,1,4,3];
console.log(streak(array)); // [5, "a"]
Demo returning both
An alternative approach. I'm converting the array to a string. The regular expression has a backrefence, which ensures that only sequences of the same character are matched. Also when exec is used with the g flag, repeated executions will continue from the end of last match, and not from the beginning.
var arr = [2,5,3,1,1,1,3,7,9,6,4,1,1,1,1,1,4,7,2,3,1,1,4,3];
var str = arr.join('');
var regex = /(.)\1*/g;
var match;
var largest = '';
while (match = regex.exec(str)) {
largest = match[0].length > largest.length ? match[0] : largest;
}
console.log(largest.length);
Your problems:
You don't store current streak
You don't specify when streak is more then older streak
Use this:
function streak(arr) {
var i,
temp,
streak = 1,
maxStreak = 0,
prevNumber,
length = arr.length;
for(i=1; i<length; i++) {
prevNumber = arr[i-1];
if (arr[i] == prevNumber) {
streak += 1;
} else {
if(streak > maxStreak) {
maxStreak = streak;
streak = 1;
}
}
}
return maxStreak;
}
Demo
You will need another two arrays here.
Store the distinct numbers from your source array using a loop
Make a second set of array which is equal to the length of the first set of array which has the distinct numbers.
Make a loop equal to the length of the first set of array and then push the values to the second set of array according to its index.
Make a loop again using the second set of array and there you will find the most occurence using the index of the second array
Finally, get from the first set of array the number using the index you got from step 4.
I did not make the code for you to try it yourself first since you are asking only for some pointers
Alternative: use regexp and converting the array to a string.
var arr = [2,5,3,1,1,1,3,7,9,6,4,1,1,1,1,1,4,7,2,3,1,1,4,3];
var str = arr.join('').match(/1+/g);
console.log(process ? process.sort().pop() : "No ocurrences");
You could take Array#reduce and return the start index of the actual same item sequence. Then check and update the counter if the item is not equal.
var array = [2, 5, 3, 1, 1, 1, 3, 7, 9, 6, 4, 1, 1, 1, 1, 1, 4, 7, 2, 3, 1, 1, 4, 3],
maxCount = 0,
maxValues;
array.reduce(function (j, a, i, aa) {
if (aa[j] === a) {
return j;
}
if (i - j === maxCount){
maxValues.push(aa[j]);
}
if (i - j > maxCount) {
maxCount = i - j;
maxValues = [aa[j]];
}
return i;
}, -1);
console.log(maxCount);
console.log(maxValues);
My proposal:
function getLongestRow(inputArray) {
// Initialize dummy variables
var start = inputArray[0], curRowLen = 0, maxRowLen = 0, maxRowEle = 0;
// Run through the array
for(var i = 0;i < inputArray.length;i++) {
// If current Element does not belong to current row
if(inputArray[i] != start) {
// If current row is longer than previous rows, save as new longest row
if(curRowLen > maxRowLen) {
maxRowLen = curRowLen;
maxRowEle = start;
curRowLen = 1;
}
// Start new row
start = inputArray[i];
} else {
// Current element does belongt to current row, increase length
curRowLen++;
}
}
// Check whether last row was longer than previous rows
if(curRowLen > maxRowLen) {
maxRowLen = curRowLen;
maxRowEle = start;
}
// Return longest row & element longest row consits of
console.log('The longest row in your array consists of '+maxRowLen+' elements of '+maxRowEle+'.');
}
JsFiddle: http://jsfiddle.net/hdwp5/
Here's a way to do it:
var values = function(obj) {
var res = [];
for (var i in obj) {
if (obj.hasOwnProperty(i)) {
res.push(obj[i]);
}
}
return res;
};
var countStreak = function(xs) {
var res = xs.reduce(function(acc, x, i) {
if (x === xs[i+1]) {
acc[x] = acc[x]+1 || 2;
} else {
acc[x] = acc[x]-1 || 0;
}
return acc;
},{})
return Math.max.apply(0, values(res));
};
var ns = [2,5,3,1,1,1,3,7,9,6,4,1,1,1,1,1,4,7,2,3,1,1,4,3]
countStreak(ns) //=> 5
You can use fewer iterations by looking ahead at all matches from a given index,
and jumping ahead to the next non-matching item's index.
You can also quit when there are less items left than the maximum you have found.
function maxRepeats(arr){
var L= arr.length, i= 0,
max= 1, count= 0;
while(L-i > max){
while(arr[i+count]=== arr[i])++count;
if(count > max) max= count;
i+= count;
count= 0;
}
return max;
}
var A= [2, 5, 3, 1, 1, 1, 3, 7, 9, 6, 4, 1,
1, 1, 1, 1, 4, 7, 2, 3, 1, 1, 4, 3];
maxRepeats(A); returns 5
Finding multiple items that repeat the max number of times is not so easy,
since you have to find the max number before you can list them.
If you really only need the max number, ignore this:
function mostRepeats(arr, maximum){
var i= 0, max= maximum || 1,
L= arr.length-max,
count= 0, index= [];
while(i<L){
while(arr[i+count]=== arr[i])++count;
if(count=== maximum) index.push(arr[i]+' starting at #'+i);
else if(count > max) max= count;
i+= count;
count= 0;
}
if(max===1) return 'No repeats';
return maximum? max+' repeats of: '+index.join(', '): mostRepeats(arr, max);
}
var A= [2, 5, 3, 1, 1, 1, 3, 7, 9, 6, 4, 1, 1, 1,
1, 1, 4, 7, 2, 3, 3, 3, 3, 3, 1, 1, 4, 3];
mostRepeats(A);returns:
5 repeats of: 1 starting at #11, 3 starting at #19
Unfortunately I can't comment yet due to lack of reputation so I will post this as an answer. For my task Robbie Averill's solution was perfect, but it contains a little bug. I had array that consisted of 2 values - 0 & 1.5, but above-mentioned code was counting only "1.5" values although I had "0" repeating in a higher streak. Problem was that value wasn't doing strict comparison here:
if(temp != '' && temp == arr[i]) {
and the fix was simple: if(temp !== '' && temp == arr[i]) {
I've updated Robbie's jsfiddler with this fix: http://jsfiddle.net/d5X2k/5/
Unfortunatly, a question has been marked as duplicate, but it was not the same as this one. So I must put my answer here, sorry…
let tab = [0,0,0,1,1,1,0,0,0,0,1,0,1,1,1,1,1]
, arr = []
, n = 0
, res = null ;
for(let i of tab)
{
if ( i ) { ++ n }
else if ( n ) { arr.push(n) ; n = 0 }
}
arr.push(n) ;
res = Math.max(...arr);
console.log("Streak with 1 is ", Math.max(...arr));
It's a better solution than with reduce, slower, as you can see:
let tab = [0,0,0,1,1,1,0,0,0,0,1,0,1,1,1,1,1];
let arr = [];
let n = 0;
let res = null;
let loop = 0;
let start = new Date().getTime();
while (loop < 1000000){
++ loop;
arr = [];
for(let i of tab)
{
if ( i ) { ++ n }
else if ( n ) { arr.push(n) ; n = 0 }
}
arr.push(n);
res = Math.max(...arr);
}
let end = new Date().getTime();
console.log("laps old fashion = ", end - start);
loop = 0;
let streaks = null;
start = new Date().getTime();
while (loop < 1000000){
++ loop;
streaks = tab.reduce((res, n) =>
(n ? res[res.length-1]++ : res.push(0), res)
, [0]);
res = Math.max(...streaks);
}
end = new Date().getTime();
console.log("laps reduce = ", end - start);
console.log("Streak with 1 is ", Math.max(...arr));
Input array:
const seq = [
0, 0, 0,
1, 1, 1,
1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1,
];
Shortest solutions:
console.log(Math.max(...Array.from(seq.join("").matchAll(/(.)\1+/g), m=>m[0].length)))
Alternative with regexp (spoiler: it's ~25%, slower than solution with reduce(). See "Modern approach with reduce()" below):
const longestSeq = (seq) => {
let max = 0;
seq.join("").replace(/(.)\1+/g, m=> max = Math.max(max, m.length));
return max;
};
Straightforward, old-school style, human readable and fastest solution:
let longestSeq = () => {
let maxCount = 0,
curCount = 0,
curItem, prevItem,
l = seq.length+2, // +1+1 to finish last sequence and compare 'undefined' with previous
i = 0;
for (; i < l; ++i) {
curItem = seq[i];
if (curItem === prevItem) ++curCount;
else {
if (curCount > maxCount) maxCount = curCount;
curCount = 1;
prevItem = curItem;
}
}
return maxCount;
}
Modern approach with reduce() (just very little slower than old-school code above):
const longestSeq = (seq) => seq
.reduce(
({count, max}, item) => item === 0
? { count: ++count, max: Math.max(count, max) }
: { count: 0, max: max },
{ count: 0, max: 0} )
.max;
Performance test, Reduce() vs old-school for(): https://jsbench.me/ifkgsin56z/1
Related
This question already has answers here:
Move zeroes to end of array in javascript - how to return nothing?
(21 answers)
Closed last year.
Trying to remove all 0's from an array and return them in the same array
So for example if I have this as an array
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]
I would get this:
let arrThree = [9,9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0,0]
This is what I wrote:
var remove = function (arr) {
let test = [];
for(let i = 0; i < arr.length; i++){
arr[i] === 0 ? test.push(arr.splice(i,1)) : false //if i is 0 then we want to push that into another array
}
arr.push(...test)
return [].concat(...arr)
}
When I run this function I get this
[
9, 9, 1, 2, 1, 1, 3,
1, 9, 0, 9, 0, 0, 0,
0, 0, 0, 0, 0, 0
]
Not sure where I am going wrong?
You need only two iterations, one for finding non zero values and another to put zeroes to the right side until end of the array. You need no array pushing or splicing.
const
move0 = array => {
let i = 0,
j = 0;
while (i < array.length) {
if (array[i]) array[j++] = array[i];
i++;
}
while (j < array.length) {
array[j] = '#'; // in reality it is zero
j++;
}
},
array = [9, 0, 9, 1, 2, 1, 1, 3, 1, 9, 0, 0, 9, 0, 0, 0, 0, 0, 0, 0];
move0(array)
console.log(...array);
If you don't need to have any sorting on the non-zero elements, a rather efficient solution would be to swap the left-most 0 with the right-most non-zero element. Once your indices for tracking where you are on the left and right cross you'll know you're done.
function moveZeros(arr) {
let i = 0;
let j = arr.length - 1;
while(i < j) {
// Found a 0 to the left of a non-zero, swap.
if(arr[i] == 0 && arr[j] != 0) {
let tmp = arr[j];
arr[j] = arr[i];
arr[i] = tmp;
}
// Find a zero
if(arr[i] != 0) {
i++;
}
// Find a non-zero
if(arr[j] == 0) {
j--;
}
}
return arr;
}
console.log(moveZeros([1,2,0,3,0,0,0]));
console.log(moveZeros([9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0]));
The issue with your code is you change the length of arr with arr.splice(i,1). This messes up the loop condition i < arr.length.
To fix your code, you can loop backwards through the array. So as the length of the array shortens, i is still valid.
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
var remove = function(arr) {
let test = [];
for(let i = arr.length - 1; i >= 0; --i) {
if (arr[i] === 0) test.push(arr.splice(i, 1)[0]);
}
return arr.concat(test);
}
console.log(remove(arrThree));
There are a few other ways to do this. One is to use filter to create 2 arrays - one with no 0 and one with all 0 and join them:
let arrThree = [9,0,9,1,2,1,1,3,1,9,0,0,9,0,0,0,0,0,0,0];
let remove = (arr) => arr.filter(i => i != 0).concat(arr.filter(i => i == 0));
console.log(remove(arrThree));
Question
Given an array of integers, find the one that appears an odd number of times.
There will always be only one integer that appears an odd number of times.
My Attempt
function findOdd(A) {
let newArr = A.sort();
let altArr = [];
let count = 0;
let firstCharacter = newArr[0];
for (let i = 0; i < newArr.length; i++) {
if (newArr[i] == firstCharacter) {
count++;
} else {
let subArr = newArr.slice(newArr[0], count);
console.log(subArr);
altArr.push(subArr);
count = 0;
firstCharacter = newArr[i];
}
}
for (let i = 0; i < altArr.length; i++) {
if (altArr[i].length % 2 != 0) {
return altArr[i][0];
}
}
}
console.log(findOdd([20, 1, -1, 2, -2, 3, 3, 5, 5, 1, 2, 4, 20, 4, -1, -2, 5]))
Problem
I used console logs which showed me that the slices are returning an empty array Which I think is why this algorithm is broken. But why does it return an empty array? And is there any other mistakes i have missed?
You are making this problem much more complicated than it actually is. A naive implementation would simply use an object to store the frequency of each element and then iterate over it at the end to find the element that appeared an odd amount of times.
function findOdd(arr) {
const freq = {};
for(const num of arr){
freq[num] = (freq[num] || 0) + 1;
}
return +Object.keys(freq).find(num => freq[num] % 2 == 1);
}
A more efficient implementation could leverage the properties of the bitwise XOR (^), namely the fact that a ^ a == 0, a ^ 0 == a, and that the operation is commutative and associative, leading to the solution of applying XOR on each element of the array to obtain the answer.
function findOdd(arr) {
return arr.reduce((a,c)=>a ^ c, 0);
}
newArr.slice(newArr[0], count);
slice takes 2 parameters and they need to be index, not an actual value. So the above code is definitely not correct.
I think you can use dictionary to simplify this algorithm. Here is my approach.
function findOdd(A) {
const appearances = {};
A.forEach(val => {
appearances[val] = (appearances[val] || 0) + 1;
});
const oddNumbers = Object.keys(appearances).filter(key => appearances[key] % 2 != 0);
return oddNumbers.length > 0 ? oddNumbers[0] : NaN;
}
After sorting, you could take a single loop and check the value against the last value (initialize without a value).
function findOdd(array) {
let count = 0;
let last;
array.sort();
for (let i = 0; i < array.length; i++) {
if (array[i] === last) {
count++;
continue;
}
if (count % 2) return last;
last = array[i];
count = 1;
}
return last;
}
console.log(findOdd([20, 1, -1, 2, -2, 3, 3, 5, 5, 1, 2, 4, 20, 4, -1, -2, 5]))
.as-console-wrapper { max-height: 100% !important; top: 0; }
I was doing Move Zeroes in leetcode.
I write a function to solve but leetcode said it's a wrong answer.
Could someone see what is wrong in my code?
Requirement:the original array must be mutated
Input:[0,1,0,3,12]
Output:[1,3,12,0,0]
Input:[2,1]
Output:[1,2]
Here is my JS:
var moveZeroes = function(nums) {
var ZeroArray=[]
for(let i=0;i<nums.length;i++){
if(nums[i]===0){
ZeroArray.push(nums[i])
nums.splice(i,1);
}
}
nums.sort((a,b)=>(a-b))
for(let j=0;j<ZeroArray.length;j++){
nums.push(ZeroArray[j])
}
return nums;
};
console.log(moveZeroes([0,1,0,3,12])); //Should return [ 1,3,12,0,0]
console.log(moveZeroes([2,1]));//Should return [1,2]
Your
nums.shift(nums[i]);
will remove (and discard) whatever exists at the 0th index in nums at the time. It would probably be easier to push to a different array if the num is not 0, then combine the arrays at the end (no sorting):
var moveZeroes = function(nums) {
var ZeroArray = []
var nonZeroArray = [];
for (let i = 0; i < nums.length; i++) {
if (nums[i] === 0) {
ZeroArray.push(nums[i])
} else {
nonZeroArray.push(nums[i]);
}
}
return [...nonZeroArray, ...ZeroArray];
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Or, if you do want to .sort, .sort only:
var moveZeroes = function(nums) {
nums.sort((a, b) => (a === 0) - (b === 0));
return nums;
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Do check === 0 - otherwise, your
.sort((a,b)=>(a-b))
will put negative numbers after the 0s, when you want 0s to come at the end regardless.
If you also need to preserve the original order of non-zeros, iterate over the array, splice out 0s while keeping track of how many you remove, then push them at the end:
var moveZeroes = function(nums) {
let count = 0;
for (let i = nums.length - 1; i >= 0; i--) {
if (nums[i] === 0) {
nums.splice(i, 1);
count++;
}
}
nums.push(...new Array(count).fill(0));
return nums;
};
console.log(moveZeroes([0, 1, 0, 3, 12])) //Should return [ 1,3,12,0,0]
Array.shift() removes the first element from an array, you most likely want to use Array.splice(i, 1)
Use filter to filter all the non zero elements and then append remaining array size with zeros.
let arr = [0,1,0,3,12];
let filtered = arr.filter(item => item !== 0);
let result = [...filtered, ...(new Array(arr.length - filtered.length).fill(0))]
console.log(result);
Using splice remove zero and count the spiced values. In a loop push the zeroes in the array equal to the count
var a=[0,1,0,3,12];
var count=0;
a.forEach(e=>{
if(e==0){
a.splice(a.indexOf(e),1)
count++
}})
for(var i=0;i<count;i++)
a.push(0)
console.log(a)
You could take a single loop approach with an additonal variable for the next index for swapping the values.
This approach works in situ, as the specs requires.
/**
* #param {number[]} nums
* #return {void} Do not return anything, modify nums in-place instead.
*/
var moveZeroes = function(nums) {
var i, j = 0;
for (i = 0; i < nums.length; i++) {
console.log(...nums); // look!
if (nums[i] !== 0) { // check
[nums[j], nums[i]] = [nums[i], nums[j]]; // swap items
j++; // increment target
}
}
},
array = [0, 1, 0, 3, 12];
moveZeroes(array)
console.log(...array); // [1, 3, 12, 0, 0]
here is code to remove zeros in c++
void pushZerosToEnd(int arr[], int n)
{
int count = 0;
for (int i = 0; i < n; i++)
if (arr[i] != 0)
arr[count++] = arr[i];
while (count < n)
arr[count++] = 0;
}
int main()
{
int arr[] = {1, 9, 8, 4, 0, 0, 2, 7, 0, 6, 0, 9};
int n = sizeof(arr) / sizeof(arr[0]);
pushZerosToEnd(arr, n);
cout << "Array after pushing all zeros to end of array :n";
for (int i = 0; i < n; i++)
cout << arr[i] << " ";
return 0;
}
var a = [1, 2, 0, 0, 3, 0, 3, 0, 2, 0, 0, 0, 5, 0];
function moveZero(b) {
for (var i = b.length - 1; i >= 0; i--) {
if (b[i] === 0) {
b.splice(i, 1);
b.push(0);
}
}
return b;
}
console.log(moveZero(a));
I have a few arrays, which are filled with different values every new time. So the array sometimes contains more than one of the same value. So it could look like this: [0, 0, 0, 2, 3, 0]. I want to be able to remove one instance of a target value. For example, if the target were 0, the array might then look like this: [0, 0, 2, 3, 0].
At the moment I am working with this code:
var new_list = grades.filter(e => e !== grade);
Note: grades is the ArrayList I get from the database. But this line is going to remove all 0. But I only want to remove one of the 0.
EDIT:
Tried something like this:
let grades = doc.data()[grade_type] || [];
var elementIndex = grades.indexOf(grade);
grades.splice(elementIndex);
But does not work. Example ArrayList [0, 0, 0] . Output [].
~filip
After you detect which element has duplicates you can use splice
grades.splice(elementIndex,1);
You could delete the second appearance of the same value and take a flag for keeping all other values.
var array = [0, 0, 0, 2, 3, 0, 3, 3],
f = {};
array = array.filter(v => f.all || (f.all = !(f[v] = (f[v] || 0) + 1 !== 2)));
console.log(array);
Check next approach, here we loop over the array until we found the first duplicate of the element you want to remove, when we found it, we remove it using splice().
const grades = [0, 0, 1, 0, 1, 2, 3, 2, 3, 4];
const rmOneDupFrom = (arr, n) =>
{
let nCounter = 0;
for (let i = 0; i < arr.length; i++)
{
nCounter = arr[i] === n ? nCounter + 1 : nCounter;
if (nCounter > 1)
{
arr.splice(i, 1);
return;
}
}
}
console.log("Original => ", JSON.stringify(grades));
// Remove one duplicate of element 3.
rmOneDupFrom(grades, 3);
console.log("one 3 removed => ", JSON.stringify(grades));
// Remove one duplicate of element 0.
rmOneDupFrom(grades, 0);
console.log("one 0 removed => ", JSON.stringify(grades));
// Try to remove one duplicate of element 4.
rmOneDupFrom(grades, 4);
console.log("none removed (4 hasn't duplicates) => ", JSON.stringify(grades));
You should note that this approach mutates the original array, in case you don't want that, you can make a copy of the original array before passing it to rmOneDupFrom() with slice(), example:
let grades = [0, 0, 1, 0, 1, 2, 3, 2, 3, 4];
const rmOneDupFrom = (arr, n) =>
{
let nCounter = 0;
for (let i = 0; i < arr.length; i++)
{
nCounter = arr[i] === n ? nCounter + 1 : nCounter;
if (nCounter > 1)
{
arr.splice(i, 1);
return;
}
}
}
let gradesCopy = grades.slice(0);
rmOneDupFrom(gradesCopy, 3);
console.log("Original => ", JSON.stringify(grades));
console.log("Copy => ", JSON.stringify(gradesCopy));
UPDATE:
The following will remove the second instance of a duplicate (the earliest we can detect that a duplicate, in fact, exists):
function removeOneTargetDuplicate(list, target) {
let result = [];
let count = 0;
for (let i = 0; i < list.length; i++) {
if (list[i] === target) {
count++;
if (count === 2) {
continue;
}
}
result.push(list[i]);
}
return result;
}
The following solution will remove the first instance of a duplicate, albeit with a bit more complexity but still with linear time complexity:
function removeOneTargetDuplicate(list, target) {
let result = [];
let duplicate = false;
for (let i = 0; i < list.length; i++) {
// duplicate will only be true if we've removed the first duplicate
if (list[i] === target && !duplicate) {
// if we've found the target, check the rest of the array for a duplicate
for (let j = i + 1; j < list.length; j++) {
if (list[j] === target) {
duplicate = true;
}
}
// if that duplicate was found, skip to the next iteration of the for loop and don't add to the result, effectively removing the first instance of the target
if (duplicate) {
continue;
}
}
result.push(list[i]);
}
return result;
}
Write a program to find count of the most frequent item of an array. Assume that input is array of integers.
Example:
Input array: [3, -1, -1, -1, 2, 3, -1, 3, -1, 2, 4, 9, 3]
Ouptut: 5
Most frequent number in example array is -1. It occurs 5 times in input array.
Here is my code:
function mostFrequentItemCount(collection) {
var copy = collection.slice(0);
for (var i = 0; i < collection.length; i++) {
var output = 0;
for (var x = 0; x < copy.length; x++) {
if (collection[i] == copy[x]) {
output++;
}
}
}
return output;
}
It seems to be just counting the reoccurrence of the first number in the array not the one that occurs the most. I can't figure out how to make it count the most occurring one.
If i didn't miss anything, and if you really want to find the count of the most frequent item of an array, i guess one approach would be this one:
function existsInCollection(item, collection) {
for(var i = 0; i < collection.length; i++) {
if(collection[i] === item) {
return true;
}
}
return false;
}
function mostFrequentItemCount(collection) {
var most_frequent_count = 0;
var item_count = 0;
var already_checked = [];
for(var i = 0; i < collection.length; i++) {
// if the item was already checked, passes to the next
if(existsInCollection(collection[i], already_checked)) {
continue;
} else {
// if it doesn't, adds to the already_checked list
already_checked.push(collection[i]);
}
for(var j = 0; j < collection.length; j++)
if(collection[j] === collection[i])
item_count++;
if(item_count > most_frequent_count)
most_frequent_count = item_count;
item_count = 0;
}
return most_frequent_count;
}
var items = [3, -1, -1, -1, 2, 3, -1, 3, -1, 2, 4, 9, 3];
alert(mostFrequentItemCount(items));
What happens here is:
On each item ('i' loop), it will run another loop ('j') through all items, and count how many are equal to the [i] item. After this second loop, it will be verified if that item count is greater than the most_frequent_count that we already have, and if it is, updates it.
Since we always use the same variable 'item_count' to check each number count, after the verification of each number we reset it to 0.
This may not be the best answer, but it was what occurred me at the moment.
EDIT:
I added a function to check if an item already exists in a list, to avoid the loop from check the same item again.
The problem is that you override the output variable each loop iteration, so after the for loop ends your output variable holds occurrences of the last element of input array.
You should use variables like var best_element = collection[0] and var best_element_count = -1 (initialized like this). After each inner loop you check if algo found any better solution (best_element_count < output) and update best_element.
Edit: following #Alnitak comment you should also reset the output variable after each inner loop iteration.
First you will need to construct a collection (or object) that contains the element and the count of occurances. Second you will need to iterate the result to find the key that has the highest value.
JSFiddle
function mostFrequentItemCount(collection) {
var output = {};
for (var i = 0; i < collection.length; i++) {
var item = collection[i];
if (!(item in output))
output[item] = 0;
output[item]++;
}
var result = [0, 5e-324];
for (var item in output) {
if (output[item] > result[1]) {
result[0] = parseFloat(item);
result[1] = output[item];
}
}
return result;
}
var input = [3, -1, -1, -1, 2, 3, -1, 3, -1, 2, 4, 9, 3];
var result = mostFrequentItemCount(input);
console.log(result);
The snippet above simply creates a new object (output) which contains a property for each of the unique elements in the array. The result is something like.
2:2
3:4
4:1
9:1
-1:5
So now we have an object with the property for the number and the value for the occurances. Next we then interate through each of the properties in the output for(var item in output) and determine which value is the greatest.
Now this returns an array with the value at index 0 being the number and the value at index 1 being the count of the element.
Check this solution.
var store = [3, -1, -1, -1, 2, 3, -1, 3, -1, 2, 4, 9, 3];
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.
}
}
alert(max);
So this update to your method will return an object with each key and the count for that key in the array. How you format an output to say what key has what count is up to you.
Edit: Updated to include the complete solution to the problem.
function mostFrequentItemCount(collection) {
var copy = collection.slice(0);
var results = {};
for (var i = 0; i < collection.length; i++) {
var count = 0;
for (var x = 0; x < copy.length; x++) {
if (collection[i] == copy[x]) {
count++;
}
}
results[collection[i]] = count;
}
return results;
}
var inputArray = [3, -1, -1, -1, 2, 3, -1, 3, -1, 2, 4, 9, 3];
var occurances = mostFrequentItemCount(inputArray);
var keyWithHighestOccurance = Object.keys(occurances).reduce(function(a, b){ return occurances[a] > occurances[b] ? a : b });
var highestOccurance = occurances[keyWithHighestOccurance];
console.log("Most frequent number in example array is " + keyWithHighestOccurance + ". It occurs " + highestOccurance + " times in the input array.");