I have the following code
let range = [1,2,3];
let multiples = [1,2,3,4,5,6,2,4,6,3,6];
I want to find the first number in the multiples array that occurs range.lenght times (3);
I want to start with multiples[0] check how many times it occurs in multiples, if it occurs 3 times I want to return multiples[0], if it is less than 3 times, I want to check how many times multiples[1] occurs in the multiples array. If multiples[1] occurs 3 times I want to return multiples[1], else I move on to check multiples[2], etc. until I find a number that occurs 3 times. In the code above I should return 6.
I've looked at
How to count the number of certain element in an array?
and
Idiomatically find the number of occurrences a given value has in an array
and
get closest number out of array
among other research but have not figured it out yet.
I tried to simplify the question as much as possible. But if more info is needed it relates to this challenge on freeCodeCamp. Where I am at with my code is
function smallestCommons(arr) {
let sortArr = arr.sort((a, b) => a - b);
console.log(sortArr);
let range = [];
for (let i = sortArr[0]; i <= sortArr[1]; i++) {
range.push(i);
}
console.log("range = " + range);
let maxNum = range.reduce( (a, b) => a * b);
console.log("maxNum = " + maxNum);
let multiples = [];
for (let i = 0; i < maxNum; i++) {
let j = 0;
do {
multiples.push(j + range[i]);
j += range[i];
} while (j < maxNum);
//j = 0;
}
for (let i = 0; i < multiples.length; i++) {
let numberToFind = multiples[i];
/*stuck here hence my question, maybe I shouldn't even start with a for loop*/
//tried reduce, forEach, filter, while loop, do while loop
}
console.log("multiples = " + multiples);
}
console.log(smallestCommons([1,3]));
The logs are
1,3
range = 1,2,3
maxNum = 6
multiples = 1,2,3,4,5,6,2,4,6,3,6,NaN,NaN,NaN
What you can do is, first split your string with , and then using below function loop for check.
function countLength(arr, checkNumber) {
var count = 0;
for (var i = 0; i < arr.length; i++) {
if (arr[i] === checkNumber) {
count++;
}
}
return count;
}
countLength(list, NUMBER YOU WANT TO CHECK);
And if you want to check first number occur for 3 time then you need to make change in function and introduce .map or .filter in action to count number.
Example
const multiples = [1,2,3,4,5,6,2,4,6,3,6];
let occurance_arr=[];
const aCount = [...new Set(multiples)].map(x => {
if(multiples.filter(y=> y==x).length == 3) {
occurance_arr.push(x);
}
});
console.log(occurance_arr);
Above code will give you 6 in console, if you have multiple value then 0th element is the answer you are looking for which is first three time occurrence of item.
You can loop through your list keeping an object that maps each number to the number of times you've seen it. You can check the counts object as you loop, so if you see a number and the count is one less than your target, you can return it. If you make it through the loop without returning you didn't find what you're looking for — return something sensible :
let range = [1,2,3]
let multiples = [1,2,3,4,5,6,2,4,6,3,6]
function findFirstMult(arr, len){
let counts = {} // to keep track of how many times you've seen something
for (let n of arr){ // loop throught the array
if (!counts[n]) counts[n] = 0 // if it's then first time you've seen n, defined that key
if (counts[n] == len - 1) return n // found it
counts[n] +=1 // otherwise increase the count
}
return undefined
}
console.log(findFirstMult(multiples, range.length))
This will require only one loop through the array in the worse case and will return early if if finds something.
Iterating through a javascript array which has some data in, and some null or not defined values also, is giving funny behaviors with a for loop, but not with a while loop. It is not returning when it should and is stuck in an infinite loop
I have investigated the outputs extensively, the condition whether the number exists in the array is never evaluated to be true, only ever false, but it sometimes enters the if statement region as if it is true. It is seemingly arbitrary.
//function called within this code
function randomArrayOfIndexes() {
var randNumbArray = new Array(4);
var indexToAssign = Math.floor(Math.random() * Math.floor(4));
randNumbArray[0] = indexToAssign;
for (i = 1; i < randNumbArray.length; i++) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
while (arrayContains(randNumbArray, indexToAssign)) {
indexToAssign = Math.floor(Math.random() * Math.floor(4));
}
randNumbArray[i] = indexToAssign;
}
return randNumbArray;
}
//this works
function arrayContains(arrayin, numberIn) {
var i = arrayin.length;
while (i--) { //takes one from i so highest index is accurate on first iteration
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
//this doesn't... not even backwards like the above iteration
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
At first each function above is passed in an array with [int value, null, null, null], and a random number; when the function returns, the next null value is filled with the random number that doesn't exist in it already, so [int value, int value, null, null]... until all values are filled... the final array is filled with unique random numbers from 0 to 3, to provide an index for a piece of data in another array... to make sure that it is only used once in the program I am writing.
I would expect it to return true if the number passed in is already in there, another random number then generated outside of the broken function, and the process repeated until a unique random number is found. When it is found, the array being passed back in will be populated at the next available index, and the process repeated. This is not happening. It is getting stuck in an infinite loop, and never returning
you are just missing a var before i:
function arrayIncludes(arrayin, numberIn) {
for (var i = 0; i < arrayin.length; i++) {
// in ^ here
if (arrayin[i] === numberIn) {
return true;
}
}
return false;
}
You may also declare it before loop, like
var i;
for (i = 0; i < arrayin.length; i++) {
...
By the way, this way of generating random numbers without duplicates is very inefficient, I suggest something like having an array of 0-3 (in your current example) or 0-n and then just randomly taking items out of it. then you don't have to loop through the whole array each time you find a new number. every time you just find a random index between 0 and the length of remaining items.
Imagine that the array length is 1000, and the last item remaining is a number like 100, how many times you have to find a random number and loop through whole array till your random number is 100?
var n = 5;
var a = new Array(n);
for(var i=0;i<n;i++) a[i] = i;
var result = new Array(n);
var i = n;
while(i)
{
var index = Math.floor(Math.random() * i);
result[--i] = a[index];
a.splice(index,1);
}
document.getElementById('a').innerHTML = result;
<div id="a"></div>
You need to declare variables in you loops with for i=0. if you don't do this the variable is global and when you use the same loop variable in nested loops one can change the other.
You are using i in both loops so when you call the for loop with:
function arrayIncludes(arrayin, numberIn) {
for (i = 0; i < arrayin.length; i++) {
// etc
}
You set i back to 0 ad iterate it — this is the same i you are using in randomArrayOfIndexes so it interferes with that loop. This is a common cause of hard-to-find bugs and is hy you should always declare loop variables.
Here's the bug in it's simplest form. Notice that the out loop only runs once because i is incremented in the inner loop causing the outloop to exit early:
for (i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}
If you declare the variables for for let i =, each loop gets its own version of i both loops run independently:
for (let i = 0; i < 4; i++){
console.log("out loop number: ", i)
for (let i = 0; i < 4; i++){
console.log("inner_loop: ", i)
}
}
I've a strange thing to do but I don't know how to start
I start with this vars
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
So to start all the 3 array have the same length and the very first operation is to see if there is a duplicate value in sky array, in this case the 0 is duplicated and only in this case is at the end, but all of time the sky array is sorted. So I've to remove all the duplicate (in this case 0) from sky and remove the corresponding items from base and sum the corresponding items on ite. So if there's duplicate on position 4,5 I've to manipulate this conditions. But let see the new 3 array:
var new_base = [1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var new_sky = [0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var new_ite = [139,38,13,15,6,4,6,3,2,1,2,1,1,1];
If you see the new_ite have 139 instead the 64,52,23, that is the sum of 64+52+23, because the first 3 items on sky are the same (0) so I remove two corresponding value from base and sky too and I sum the corresponding value into the new_ite array.
There's a fast way to do that? I thought a for loops but I stuck at the very first for (i = 0; i < sky.length; i++) lol, cuz I've no idea on how to manipulate those 3 array in that way
J
When removing elements from an array during a loop, the trick is to start at the end and move to the front. It makes many things easier.
for( var i = sky.length-1; i>=0; i--) {
if (sky[i] == prev) {
// Remove previous index from base, sky
// See http://stackoverflow.com/questions/5767325/how-to-remove-a-particular-element-from-an-array-in-javascript
base.splice(i+1, 1);
sky.splice(i+1, 1);
// Do sum, then remove
ite[i] += ite[i+1];
ite.splice(i+1, 1);
}
prev = sky[i];
}
I won't speak to whether this is the "fastest", but it does work, and it's "fast" in terms of requiring little programmer time to write and understand. (Which is often the most important kind of fast.)
I would suggest this solution where j is used as index for the new arrays, and i for the original arrays:
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
var new_base = [], new_sky = [], new_ite = [];
var j = -1;
sky.forEach(function (sk, i) {
if (!i || sk !== sky[i-1]) {
new_ite[++j] = 0;
new_base[j] = base[i];
new_sky[j] = sk;
}
new_ite[j] += ite[i];
});
console.log('new_base = ' + new_base);
console.log('new_sky = ' + new_sky);
console.log('new_ite = ' + new_ite);
You can use Array#reduce to create new arrays from the originals according to the rules:
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330];
var sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17];
var ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1];
var result = sky.reduce(function(r, n, i) {
var last = r.sky.length - 1;
if(n === r.sky[last]) {
r.ite[last] += ite[i];
} else {
r.base.push(base[i]);
r.sky.push(n);
r.ite.push(ite[i]);
}
return r;
}, { base: [], sky: [], ite: [] });
console.log('new base:', result.base.join(','));
console.log('new sky:', result.sky.join(','));
console.log('new ite:', result.ite.join(','));
atltag's answer is fastest. Please see:
https://repl.it/FBpo/5
Just with a single .reduce() in O(n) time you can do as follows; (I have used array destructuring at the assignment part. One might choose to use three .push()s though)
var base = [1,1,1,2,3,5,7,9,14,19,28,40,56,114,232,330],
sky = [0,0,0,3,4,5,6,7,8,9,10,11,12,14,16,17],
ite = [64,52,23,38,13,15,6,4,6,3,2,1,2,1,1,1],
results = sky.reduce((r,c,i) => c === r[1][r[1].length-1] ? (r[2][r[2].length-1] += ite[i],r)
: ([r[0][r[0].length],r[1][r[1].length],r[2][r[2].length]] = [base[i],c,ite[i]],r),[[],[],[]]);
console.log(JSON.stringify(results));
Here is the code in question:
var L1 = [];
var Q1 = [];
function populateListOne() {
var limit = prompt("please enter a number you would like to fill L1 to.");
for (i = 2; i <= limit; i++) {
L1[i] = i;
}
for (n = 2; n <= L1.length; n++) {
var count = 2;
if (n == count) {
var index = L1.indexOf(n);
L1.splice(index, 1);
Q1[n] = n;
count = count + 1;
}
for (j = 0; j <= L1.length; j++) {
if (L1[j] % 2 == 0) {
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
}
document.getElementById("demo").innerHTML = "iteration " + "1" + ": " + L1 + " Q1 = " + Q1;
}
I’m currently working on a homework assignment where I have to setup a queue. All is explained in my JSFiddle.
Problem description
Essentially, the part I’m stuck on is iterating through each instance of the array and then taking the value out if the modulus is identical to 0. However, as you can see when I run the program, it doesn’t work out that way. I know the problem is in the second for loop I just don’t see what I’m doing wrong.
The way I read it is, if j is less than the length of the array, increment. Then, if the value of the index of L1[j] modulus 2 is identical to 0, set the value of secondIndex to whatever the index of j is. Then splice it out. So, theoretically, only numbers divisible by two should be removed.
Input
A single number limit, which will be used to fill array L1.
L1 will be initialized with values 2, 3, ... limit.
Process
Get the starting element of array L1 and place it in array Q1.
Using that element, remove all values in array L1 that are divisible by that number.
Repeat until array L1 is empty.
You're going to have issues with looping over an array if you're changing the array within the loop. To help with this, I tend to iterate from back to front (also note: iterate from array.length - 1 as the length element does not exist, arrays are key'd from 0):
for(j = L1.length - 1; j >=0 ; j--)
For your first loop, you miss the elements L1[0] and L1[1], so I would change the first loop to:
L1 = [];
for(i = 2; i <= limit; i++)
{
L1.push(i);
}
In this section:
for(j = 0; j <= L1.length; j++){
if(L1[j] % 2 == 0)
{
var secondIndex = L1.indexOf(j);
L1.splice(secondIndex, 1);
}
}
you should splice with j instead of secondIndex.
Change L1.splice(secondIndex, 1); to L1.splice(j, 1);
Array indices and putting entries
You initial code used an array that was initialized to start at index 2. To avoid confusion, of what index to start at, start with index 0 and iterate until array.length instead of a predefined value limit to ensure that you go through each element.
The following still works but will be more of a headache because you need remember where to start and when you will end.
for (i = 2; i <= limit; i++) {
L1[i] = i; // 'i' will begin at two!
}
Here's a better way:
for (i = 2; i <= limit; i++) {
// 'i' starts at 2 and since L1 is an empty array,
// pushing elements into it will start index at 0!
L1.push(i);
}
Use pop and slice when getting values
When you need to take a peek at what value is at the start of your array, you can do so by using L1[0] if you followed my advice above regarding array keys.
However, when you are sure about needing to remove the starting element of the array, use Array.slice(idx, amt). idx specifies which index to start at, and amt specifies how many elements to remove beginning at that index (inclusive).
// Go to 1st element in L1. Remove (1 element at index 0) from L1.
var current = L1.splice(0, 1);
Use the appropriate loops
To make your life easier, use the appropriate loops when necessary. For loops are used when you know exactly how many times you will iterate. Use while loops when you are expecting an event.
In your case, 'repeat until L1 is empty' directly translates to:
do {
// divisibility checking
} while (L1.length > 0);
JSFiddle
Here's a complete JS fiddle with in-line comments that does exactly what you said.
I think the code(below) is optimized (just use less variables than my initial version of the same logic).
How do I really know if its properly optimized ?
What factors should I consider during optimization ?
Here is the code (
also on jsfiddle )
function process(arr){
var processed = [];
for(var i=0,len=arr.length;i<len;i++){
if(processed.indexOf(arr[i]) < 0){
var nodes = findIndexes(arr,arr[i]);
if(nodes.length > 1){
for(var j=0,jlen=nodes.length;j<jlen;j++){
arr[nodes[j]] = arr[nodes[j]] + '(' + ( j + 1 ) + ')';
}
}
processed.push(arr[i]);
}
}
return arr;
}
function findIndexes(arr,val){
var node = [];
for(var i=0,len=arr.length;i<len;i++){
if(arr[i] === val){
node.push(i);
}
}
return node;
}
// input
var arr = ['aa','bb','bb','aa','cc','dd','cc','ff']
console.log(process(arr));
//output: ["aa(1)", "bb(1)", "bb(2)", "aa(2)", "cc(1)", "dd", "cc(2)", "ff"]
Here is the explanation of the code. 'process' function looks for the same values inside array and for every same values it changes the value by post pending a number to that values, "number" indicates the count of the value as it found in array.
for example
arr = ["x","x","y","z"] will return ["x(1)","x(2)","y","z"]
"y" and "z" are unchanged because they appeared only once.
To optimize I have used an array named as processed that is used to hold values that are just processed inside main for loop, so in next iterations it can be determined that the new iteration value is already processed or not by checking through the array.indexOf method, if the value is already processed then it can safely skip the underlying logic (if/for statements).
Now I have no idea how to further optimize it other than changing the whole process logic.
Optimizations in a broad sense will involve simplifying code, precomputing results which are repeatedly reused, and organizing code so more results can be reused.
Your fiddle code produced following result on analysis.
Logical LOC: 26
Mean parameter count: 3
Cyclomatic complexity: 7
Cyclomatic complexity density: 27%
Maintainability index: 104
Lines of Code (LOC)– Indicates the approximate number of lines in the code. The count is based on the IL code and is therefore not the exact number of lines in the source code file. A very high count might indicate that a type or method is trying to do too much work and should be split up. It might also indicate that the type or method might be hard to maintain.
Maintainability Index – Calculates an index value between 0 and 100 that represents the relative ease of maintaining the code. A high value means better maintainability. Color coded ratings can be used to quickly identify trouble spots in your code. A green rating is between 20 and 100 and indicates that the code has good maintainability. A yellow rating is between 10 and 19 and indicates that the code is moderately maintainable. A red rating is a rating between 0 and 9 and indicates low maintainability.
Cyclomatic Complexity – Measures the structural complexity of the code. It is created by calculating the number of different code paths in the flow of the program. A program that has complex control flow will require more tests to achieve good code coverage and will be less maintainable.
Check code complexities using online tool for your javascript code.
Reference : Link1,Link 2
Javascript optimiser page
Reference(Provides you with different techniques that you should keep in mind while optimising)
You can do it in a single loop:
function process2(arr) {
var out = arr.slice(0),
seen = {},
len = arr.length,
i, key, item, count;
for (i = 0; i < len; ++i) {
key = out[i];
item = seen[key];
if (!item) {
// firstIndex, count
seen[key] = item = [i, 0];
}
count = ++item[1];
if (count > 1) {
if (count === 2) {
out[item[0]] = key + '(1)';
}
out[i] = key + '(' + count + ')';
}
}
return out;
}
// input
var arr = ['aa', 'bb', 'bb', 'aa', 'cc', 'dd', 'cc', 'ff']
console.time('p2');
console.log(process2(arr));
console.timeEnd('p2');
From benchmarking, process2 is approximately 2x faster than process1. That's just a really naive first pass at the problem.
And yet another way to optimize your code with less changes:
In your specific case you go through the whole array for each new found entry although all previous entries have already been processed so it should be possible to opimize further by passing the current index to findIndexes:
function findIndexes(arr,val, fromIndex){
var node = [];
for(var i=fromIndex,len=arr.length;i<len;i++){
if(arr[i] === val){
node.push(i);
}
}
return node;
}
Currrently your code has a O(n^2) complextity. This is caused by your outer loop of arr in process then a call to findIndexes which again loops through arr.
You can simplify this to an O(n) algorithm that loops through the array twice:
function process(arr) {
var result = [];
var counter = {}, counts = {};
var len = arr.length;
for(var i = 0; i < len; i++){
var value = arr[i];
counter[value] = 1;
counts[value] = (counts[value] || 0) + 1;
}
for(var i = 0; i < len; i++){
var value = arr[i];
if(counts[value] == 1) {
result.push(value);
} else {
result.push(value + "(" + counter[value]++ + ")");
}
}
return result;
}
Here's an example that doesn't use nested loops, and uses an object to store key information:
var obj = {};
// loop over the array storing the elements as keys in the object
// if a duplicate element is found, increment the count value
for (var i = 0, l = arr.length; i < l; i++) {
var key = arr[i];
if (!obj[key]) obj[key] = { count: 0, level: 0 };
obj[key].count++;
}
// remove all the key/values where the count is 1
// ie there are no duplicates
for (var p in obj) {
if (obj[p].count === 1) delete obj[p];
}
// for each element in the original array, increase its 'level'
// amend the element with the count
// reduce the count
for (var i = 0, l = arr.length; i < l; i++) {
var key = arr[i];
if (obj[key] && obj[key].count > 0) {
obj[key].level++;
arr[i] = key + '(' + obj[key].level + ')';
obj[key].count--;
}
}
DEMO