Rearranging elements of an array based on properties of indexes - javascript

I want to rearrange the elements of an integer array based on the number of factors of natural numbers.
So for example my array input would be [6, 16, 7] and output should be [7, 6, 16] because the factors of numbers are 4, 5, and 1. What would be the best way to solve it, I am thinking about two for loops, but am not fully sure, how to execute it. Here's, what I have done by now.
var number;
var factors = 0;
var array = [];
while (number != 0) {
number = +prompt("Input a natural number:");
if (number != 0) {
array.push(number);
} else {
break;
}
}
for (var i = 0; i < array.length; i++) {
var a = numOfFactors(i);
for () {
if (numOfFactors(i) > numOfFactors(j)) {
}
}
}
function numOfFactors(a) {
for (var i = a; i >= 1; --i) {
if (a % i == 0 && i >> 0) {
factors++;
}
}
return factors;
}
numOfFactors(number);
console.log(factors);
console.log(array);
Thanks
I want to rearrange the array order with for loops if that would be possible

Related

Finding occurences of each element in an array and aranging them according to the count of occurences in ascending or descending order

Task: Given an array of N elements. Find the number of occurrences of each character and print it in the decreasing order of occurrences, if 2 or more number occurs the same number of times, print the numbers in decreasing order.
Input Size : |N| <= 100000
Sample Testcase :
INPUT
3 3 4 4 7 8
OUTPUT
4 3 8 7
I am able to convert it to a map, but what further steps should I implement to get the answer?
function asc(arr) {
let map = new Map
let c = 1;
for (let i = 0; i < arr.length; i++) {
if (map.has(arr[i])) {
map.set(arr[i], map.get(arr[i]) + 1)
}
else {
map.set(arr[i], c)
}
}
let narr = [...map];
let tmp;
for (i = 0; i < narr.length; i++) {
for (j = i + 1; j < narr.length; j++) {
if (narr[i][1] > narr[j][1]) {
tmp = narr[i];
narr[i] = narr[j];
narr[j] = tmp;
}
else if ((narr[i][1] = narr[j][1])) {
if (narr[i][0] > narr[j][0]) {
tmp = narr[i];
narr[i] = narr[j];
narr[j] = tmp;
}
}
}
}
return narr;
}
arr = [3, 8, 7, 4, 7, 3, 4];
console.log(asc(arr));
The problems in the given code:
Look at this code sample:
else if ((narr[i][1] = narr[j][1])) {
if (narr[i][0] > narr[j][0]) {
tmp = narr[i];
narr[i] = narr[j];
narr[j] = tmp;
}
}
In the first line, there is a mistake: comparison mixed up with assignment. That is the reason, why the frequency of 8 in your example becomes 2.
It should be rewritten as:
else if (narr[i][1] == narr[j][1]) {
My advice:
read about sorting of the arrays in JS
The reason for this suggestion is the fact, that the sort in the language is faster, than the quadratic sort (O(n^2)), which you have implemented.

array function that generates array with subset range of numbers

I am trying to create a function that builds an array up to a number set by the function parameter, with an if condition on being included based on whether the remainder is zero. The last number in the array should be no higher than the parameter. Here's what I came up with so far --
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < array.length; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
When I console log this, with justThreesUpTo(20), I get --
// [ 3, 6, 9, 12, 15, 18, 21, 24, 27, 30, 33, 36, 39, 42 ]
I see the issue being setting the limiter at array.length, which maxes out the number of items that can be in the array, but I can't figure out what else to call to make sure the last number in the array goes no higher than the "num" parameter specified by the function call. Any ideas?
Setting an array's length to something before the array is populated isn't a great idea - better to just iterate over the num itself. For example
for (var i = 1; i < num; i++) {
// push to array if i % 3 === 0
Your else i won't do anything - you can just leave it off completely.
You could make your code a whole lot shorter and cleaner if you wanted:
function justThreesUpTo(num) {
const length = Math.floor(num / 3);
return Array.from({ length }, (_, i) => (i + 1) * 3);
}
console.log(justThreesUpTo(20));
Modifying an array while looping over it (or its indices, which is what you’re doing with i < array.length) is a recipe for confusion. Start with an empty array and compare with num instead:
function justThreesUpTo(num) {
var array = [];
for (var i = 1; i < num; i++) {
if (i % 3 === 0) {
array.push(i);
}
}
return array;
}
Now you can optimize the check out of that entirely by moving up the appropriate amount each time.
function justThreesUpTo(num) {
var array = [];
for (var i = 3; i < num; i += 3) {
array.push(i);
}
return array;
}
(In your original code, the entire first num holes created by array.length = num; are unused and get spliced off, and else i does nothing.)
You can try with a simple while loop
function justThreesUpTo(num) {
var array = [];
var i = 0;
while (i < num) {
if(i % 3 === 0){
array.push(i);
}
i++;
}
return array;
}
console.log(justThreesUpTo(20));
You can use map method and spread syntax in order to write a clean solution.
function justThreesUpTo(num) {
return [ ...Array(Math.floor(num/3)).keys() ].map((_,i)=> (i+1) * 3);
}
console.log(justThreesUpTo(20));
Hmm. Looks like it was a pretty simple solution. Changed the limiter from "array.length" to "num", and it worked fine.
function justThreesUpTo(num) {
var array = [];
array.length = num;
for (i = 1; i < num; i++) {
if(i % 3 === 0){
array.push(i);
}
else i;
}
array.splice(0, num);
return array;
}
Never mind!
Use while with i+=3; inside the while loop:
function justThreesUpTo(num) {
var array = [];
var i = 0;
while(i<num){
array.push(i);
i+=3;
}
return array;
}
console.log(justThreesUpTo(20));

An array of primes generated from a given array (JavaScript)

I am trying to take a given array and iterate through it to create a new array containing only the numbers that are prime from the given array.
What I'm not sure of is the syntax for doing so - I know this is butchered and wrong, but I'm not sure how to fix it? Or if I'm even going about it the right way.
var myArray = isPrime([1,5,17,25,30])
console.log(myArray)
function isPrime(array){
var primes = [];
for(var i = 0; i < array.length; i++){
if(array[i] /= 1 || array[i] / 1 == array[i]){
primes.push([i]);
}
}
return primes;
}
A simple way to do it is creating a isElementPrime(number) function that tells if the number is prime or not (find an implementation here), and loop through it!
function isPrime(array){
var primes = [];
for(var i = 0; i < array.length; i++){
if(isElementPrime(array[i]){
primes.push(array[i]);
}
}
return primes;
}
The idea is to divide the number by every number smaller than it and greater than 1 and see if there is a remainder.
Using filter you can apply this to all elements in the array;
See example:
function isPrime(element) {
for(var i = 2; i < element; i++) {
if(element % i === 0) {
return false;
}
}
return element !== 1;
}
var array = [1, 5, 17, 25, 30];
var primes = array.filter(isPrime);
console.log("array: " + array);
console.log("primes: " + primes);

More efficient solution than many loop iterations with JavaScript

I have written an algorithm that returns the smallest common multiple of two integers that can be evenly divided by both, and can also be evenly divided by all sequential integers in the range between the initial two integers.
My algorithm works well for numbers where the smallest common multiple is a reasonably low number. For numbers where the smallest common multiple is a very large number (ex for [1,13] its 360360) my algorithm breaks because it is dependant on running more and more for loops.
I have posted my code below. It seems very long, but the problem section is near the beginning, and the rest of the code is added for context.
Is there a more efficient solution that running more and more loop iterations to return larger numbers?
// If mystery failure occurs, examine i & j loop limits.
function smallestCommons(arr) {
var firstArray = [];
var secondArray = [];
var commonNums = [];
var sequential = [];
// Sort the array from lowest to highest
arr.sort(function(a,b) {
return a-b;
});
// Assing arr values to vars so that original data stays intact
var array0 = arr[0];
var array1 = arr[1];
//console.log(arr);
// Find all multiples of both inputs.
// THIS IS THE PROBLEM SECTION
for (var i = 0; i < 1000000; i++) {
firstArray.push(arr[0] * (i+1));
}
for (var j = 0; j < 1000000; j++) {
secondArray.push(arr[1] * (j+1));
}
// THAT WAS THE PROBLEM SECTION
// Find common multiples.
for (var k = 0; k < firstArray.length; k++) {
for (var l = 0; l < secondArray.length; l++) {
if (firstArray[k] == secondArray[l]) {
commonNums.push(firstArray[k]);
} // End if.
} // End l loop.
} // End k loop.
// Find sequential numbers in range between input parameters.
for (var m = 0; m < array1; m++) {
if (array0 + 1 !== array1) {
sequential.push(array0 += 1);
} // End of if.
} // End of m loop.
// Find commonNums divisible by arr && sequential to produce a whole number.
// commonNums [ 5, 10, 15, 20, 25, 30, 35, 40, 45, 50, 55, 60, 65, 70, 75]
// arr [1,5]
// sequential [ 2, 3, 4 ]
for (var n = 0; n < commonNums.length; n++) {
var match = true;
for (var o = 0; o < sequential.length; o++) {
for (var p = 0; p < arr.length; p++) {
if (commonNums[n] % arr[p] !== 0 || commonNums[n] % sequential[o] !== 0) {
match = false;
}
}
}
if(match) {
console.log(commonNums[n]);
}
} // End of n loop.
} // End function.
smallestCommons([1,13]);
What you do does not make a lot of sense and is really hard to read. All you need to know to solve this problem is a little bit of math. And this math tells you that:
lcm(a, b) = a * b / gcd(a, b)
lcm(a,b,c) = lcm(a,lcm(b,c))
which translates into something like this:
function gcd(a, b){
while (b !== 0) {
var tmp = a;
a = b;
b = tmp % b;
}
return a
}
function lcm(a, b){
return a * b / gcd(a, b);
}
function lcm_arr(arr){
var res = 1;
for (var i = 0; i < arr.length; i++){
res = lcm(res, arr[i]);
}
return res;
}
which gives you your results in less than a second:
lcm_arr([1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13])
Sounds like a good place to use recursion, because you have a solid base case when the number difference is one (in your example smallestCommons([12,13]); or smallestCommons([1,2]); depending on the direction), and the rest (sequentials) would be incrementing the smaller or decrementing the bigger number in recursive calls. That could save you quite a few CPU cycles.

Intersection of N sorted integer arrays with limit

Given N sorted arrays of integers (no duplicates), I'd like to calculate the first limit integers in their intersection.
For example, given the following arrays:
[2, 5, 7, 8, 10, 12, 13, 15, 20, 24]
[3, 4, 5, 6, 9, 10, 11, 17, 20]
[1, 2, 3, 5, 6, 10, 12, 20, 23, 29]
the intersection is [5, 10, 20], so if limit = 2, the result should be [5, 10].
The given arrays should not be mutated.
My attempt is below. Playground here.
Is there a more efficient (faster) way to achieve this?
Would appreciate a jsperf comparison.
function intersection(sortedArrays, limit) {
var arraysCount = sortedArrays.length;
var indices = sortedArrays.map(function(array) { return 0; });
var values, maxValue, valuesAreSame, reachedEnd, i, result = [];
while (true) {
reachedEnd = indices.some(function(index, i) {
return index === sortedArrays[i].length;
});
if (reachedEnd) {
return result;
}
values = sortedArrays.map(function(array, i) { return array[indices[i]]; });
valuesAreSame = values.every(function(value, i) { return value === values[0]; });
if (valuesAreSame) {
result[result.length] = values[0];
if (result.length === limit) {
return result;
}
for (i = 0; i < arraysCount; i++) {
indices[i]++;
}
} else {
maxValue = Math.max.apply(null, values);
for (i = 0; i < arraysCount; i++) {
if (values[i] < maxValue) {
indices[i]++;
}
}
}
}
}
console.log(intersection([[0, 3, 8, 11], [1, 3, 11, 15]], 1));
// => [3]
The first challenge is to make the function correct. Once it's correct, we can worry about the speed.
There are a few things which could trip-up a function like this:
NaN
Bad limits
Repeated numbers
Only 1 input array (or none at all)
Your original function can handle repeated numbers, such as [[9,9,9,9],[9,9,9]], but gets stuck in an infinite loop if any value is NaN, and handles a limit of 0 as if there were no limit at all.
Here's my (Mk3) attempt:
function intersection( arrs, limit ) {
var result = [], posns = [];
var j, v, next, n = arrs.length, count = 1;
if( !n || limit <= 0 ) {
return result; // nothing to do
}
if( n === 1 ) {
// special case needed because main loop cannot handle this
for( j = 0; j < arrs[0].length && result.length < limit; ++ j ) {
v = arrs[0][j];
if( v === v ) {
result.push( v );
}
}
return result;
}
for( j = 0; j < n; ++ j ) {
if( !arrs[j].length ) {
return result; // no intersection
}
posns[j] = 0;
}
next = arrs[n-1][0];
++ posns[n-1];
while( true ) {
for( j = 0; j < n; ++ j ) {
do {
if( posns[j] >= arrs[j].length ) {
return result; // ran out of values
}
v = arrs[j][posns[j]++];
} while( v < next || v !== v );
if( v !== next ) {
count = 1;
next = v;
} else if( (++ count) >= n ) {
result.push( next );
if( result.length >= limit ) {
return result; // limit reached
}
if( posns[j] >= arrs[j].length ) {
return result; // ran out of values
}
next = arrs[j][posns[j]++];
count = 1;
}
}
}
}
(fiddle: http://jsfiddle.net/kn2wz2sc/4/)
This works in much the same way as your original method, but with several optimisations. It always knows which number it is looking for next, and will quickly iterate through each array until it finds a number which is at least that big. If the number is too big, it will update the number it is looking for.
In Mk2 I took some inspiration from Casey's method of counting matches as it goes instead of checking from 0-n each time, which allows it to short-cut some comparisons (and since Casey is now using indices, both methods have become very similar). In Mk3 I've made some more micro-optimisations, incrementing the indexes eagerly so that it doesn't need an inner loop.
This is safe against all the criteria I listed above (it ignores NaN since NaN!=NaN and therefore will never be in the intersection), isn't limited to numbers, and will exit quickly once any limit is reached.
A jsperf shows that Mk3 is the fastest method so far: http://jsperf.com/sorted-intersect/5 (and it's still safe against duplicates and NaN).
Here's another algorithm, where the idea is that we count how many times we see each number. Once we see it arrs.length times, we know that it's in the intersection. If it's missing from even one list, it's not in the intersection, and we can skip to the next number in that list. It turns out to be a lot faster!
This method mutates the array, but is easier to read.
function intersection(arrs, limit) {
var intersections = [];
// Keep track of how many times we've seen the largest element seen so far.
var largest = -Infinity;
var count = 0;
while (intersections.length < limit) {
for (var i = 0; i < arrs.length; i++) {
// Drop elements less than `largest`.
while (arrs[i].length && arrs[i][0] < largest)
arrs[i].shift();
// Ignore repeated elements (not needed if you don't have repeated elements).
while (arrs[i].length >= 2 && arrs[i][0] == largest && arrs[i][1] == largest)
arrs[i].shift();
// If we ran out of elements, we're done.
if (!arrs[i].length)
return intersections;
// Look at the next element.
var next = arrs[i].shift();
if (next == largest)
count++;
else {
count = 1;
largest = next;
}
// Once we see it enough times, we can be sure it's in the intersection!
if (count == arrs.length)
intersections.push(largest);
}
}
return intersections;
}
This method doesn't, but it's harder to read.
function intersection(arrs, limit) {
var intersections = [];
var indices = [];
for (var i = 0; i < arrs.length; i++)
indices[i] = 0;
// Keep track of how many times we've seen the largest element seen so far.
var largest = -Infinity;
var count = 0;
while (intersections.length < limit) {
for (var i = 0; i < arrs.length; i++) {
// Skip past elements less than `largest`.
while (indices[i] < arrs[i].length && arrs[i][indices[i]] < largest)
indices[i]++;
// If we ran out of elements, we're done.
if (indices[i] >= arrs[i].length)
return intersections;
// Look at the next element.
var next = arrs[i][indices[i]++];
if (next == largest)
count++;
else {
count = 1;
largest = next;
}
// Once we see it enough times, we can be sure it's in the intersection!
if (count == arrs.length)
intersections.push(largest);
}
}
return intersections;
}
Faster (but by a long shot not as fast as the other answers):
function intersectMultiple(sortedArrays, limit) {
var set = {}, result = [],
a = sortedArrays.length,
l = Math.max.apply(null, sortedArrays.map(function (a) {
return a.length;
})), i, j, c = 0, val;
for (i = 0; i < l && c < limit; i++) {
for (j = 0; j < a && c < limit; j++) {
val = sortedArrays[j][i];
if (!set.hasOwnProperty(val)) set[val] = 0;
if (++set[val] === a) result[c++] = val;
}
};
return result;
}
and
var s = [
[2, 5, 7, 8, 10, 12, 13, 15, 20, 24],
[3, 4, 5, 6, 9, 10, 11, 17, 20],
[1, 2, 3, 5, 6, 10, 12, 20, 23, 29]
];
intersectMultiple(s, 2);
// [5, 10]
http://jsperf.com/intersect-multiple

Categories

Resources