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));
I'm trying to create a function that moves all 0s towards the end. I'm first counting how many zeroes are in the original array using a for loop; and also splicing the 0s using their indexes.
Then through a while loop, push 0s to the array based on the total count.
I'm struggling with trying to get the splicing to work.. I'd appreciate any input I could get.
const array = [2, 0, 0, 4, 3, 1];
const moveZeroes = (arr) => {
let zeroes = 0;
for(i=0;i<=arr.length;i++){
if(arr[i] === 0){
arr.splice(i, 1);
zeroes++;
}
}
while(zeroes > 0){
arr.push(0);
zeroes--;
}
console.log(arr);
};
moveZeroes(array);
so it's a common overseen bug that you are modifying the array on which you are iterating,
so try to print the array after every iteration of for loop and you will see that your index is incrementing but your array is decreasing in the length itself, which is causing this behavior
splice is working correctly BTW.
You can use sort() method.
const arr = [0, 0, 0, 0, 1, 0, 1];
const newArr = arr.sort((a, b) => b - a)
console.log(arr)
You just need to reduce the value of the i every time you splice the array.
function moveZero(array){
var numberofZeros = 0;
for(var i=0; i< array.length; i++){
if(array[i] == 0){
array.splice(i,1);
numberofZeros++;
i--;
}
}
while(numberofZeros > 0){
array.push(0);
numberofZeros--;
}
}
To optimize this I think you can use the sort method as answered by Vaibhav
If you find you do not have a requirement to modify the array in-place. You can create the array you are looking for like so:
const array = [0, 0, 0, 0, 1];
const moveZeroes = (arr) => {
const zeroes = 0;
const arrayWithoutZeros = array.filter(x => x !== zeroes);
const zerosRemovedCount = array.length - arrayWithoutZeros.length;
const output = arrayWithoutZeros.concat(
...Array(zerosRemovedCount).fill(zeroes)
);
console.log(output);
return output;
};
moveZeroes(array);
In-place sort solution:
const array = [2, 0, Infinity, 0, 77, 0, -454, 0, 1, 100, -4, 0, -2, 88 ];
const moveZeroes = (arr) => {
const zeroes = 0;
arr.sort((a, b) => {
if (a === zeroes) {
return 1;
}
if (b === zeroes) {
return -1;
}
return 0;
});
console.log(arr);
};
moveZeroes(array);
You can do that in one sweep. splice() is more expensive as it has to move all the elements after the section you've spliced and resize the array, and that for every zero you remove. This code costs exactly 1 write operation for each element in the array.
const array = [1, 0, 2, 0, 3, 0, 4, 0, 5, 0, 6, 0];
const moveZeroes = (array) => {
let writeIndex = 0;
for (let readIndex = 0; readIndex < array.length; ++readIndex) {
if (array[readIndex] !== 0) {
array[writeIndex++] = array[readIndex];
}
}
while (writeIndex < array.length) {
array[writeIndex++] = 0;
}
return array;
}
console.log(moveZeroes(array));
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.");
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