Code War problem
My Solution on this problem:
function numberOfPairs(gloves) {
const glove = gloves.slice().sort();
const pairs = [];
for (let i = 0; i < glove.length - 1; i++) {
if (glove[i] == glove[i+1]) {
pairs.push(glove[i]);
}
}
return pairs.length;
}
It pass the initial test but failed the attempt/random test.
2nd test
My Second Solution, I add i++. It pass the Attempt
function numberOfPairs(gloves) {
const glove = gloves.slice().sort();
const pairs = [];
for (let i = 0; i < glove.length - 1; i++) {
if (glove[i] == glove[i+1]) {
pairs.push(glove[i]);
i++ // How?
}
}
return pairs.length;
}
Can you guys help me how does i++ fix the problem.
You can also group the colors and then count the pairs using Array.prototype.reduce.
function solution(input) {
return input.reduce(
([pairs, hash], clr) => {
hash[clr] = (hash[clr] ?? 0) + 1;
return [pairs + (hash[clr] % 2 === 0 ? 1 : 0), hash];
},
[0, {}]
)[0];
}
console.log(solution(["red", "green", "red", "blue", "blue"]));
console.log(solution(["red", "red", "red", "red", "red", "red"]));
Because if you found a pair, the next element is equal to the actual and you're advancing only one element in the array at a time. If you found a pair, the next element was the one found, then you have to advance another position in the array when you found it.
Say you have this array: [1, 2, 5, 8, 9, 2, 8]
Let's number the lines to make it easier:
1 function numberOfPairs(gloves) {
2 const glove = gloves.slice().sort();
3 const pairs = [];
4 for (let i = 0; i < glove.length - 1; i++) {
5 if (glove[i] == glove[i+1]) {
6 pairs.push(glove[i]);
7 i++ // How?
8 }
9 }
10 return pairs.length;
11 }
after line 2 you will have the following sorted array:
[1, 2, 2, 5, 8, 8, 9]
with 2 pairs in it.
Then you will start iteration of the array with i = 0 so in line 6 in the first iteraction glove[i] is 1 and glove[i+1] is 2. Different, so the for continues to i = 1.
Now the if in line 6 tests glove[i] with i = 1 making glove[i] = 2 and glove[i+1] also = 2 (first pair). So it enters the if and pushes the first number to pairs: 2.
Now if i++ isn't present in line 7, what would happen is that for would countinue to i = 2 making glove[i] = 2 and glove[i + 1] = 5. But the 2 makes part of the first pair encountered. So this is incorrect. We must skip the 2nd 2 that's what i++ is line 7 is there for. It would be even worse if the 4th element in the array was 2 again because it would inform another pair when there is only one.
After this for will continue not to i=2 but correctly to i=3 testing elements 5 and 8 for the next pair.
Hope this explains clearly enough.
Given a range of numbers (1-25) how can I create a loop so that at each iteration I get a unique set of variables.
To give an example, if I was doing it with 4 numbers my variables would be:
on loop 1:
a = 1, b = 2, c = 3, d = 4,
on loop 2:
a = 1, b = 2, c = 4, d = 3
etc.
What I am trying to do is iterate over every possible number for each position (think sudoku)
so in a 3x3 grid: a = top left position, b = top middle, etc...
so similar to sudoku I would have a condition (each row = 65: a + b + c + d + e= 65)
so what I want to do is have a loop where I can assign all the values to variables:
for (something) {
var topLeft = (determined from loop)
var nextPosition = etc.
My solution is currently like so:
var numbers = [1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25];
var a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y;
var vars = [a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y];
var counter = 0;
var found = false;
while(found == false) {
for (var asdf = numbers, i = asdf.length; i--; ) {
var random = asdf.splice(Math.floor(Math.random() * (i + 1)), 1)[0];
vars[i] = random;
}
if (
{a+b+c+d+e = 65,
f+g+h+i+j = 65,
k+l+1+n+o = 65,
p+q+r+s+t = 65,
u+v+w+x+y = 65,
a+f+k+p+u = 65,
b+g+l+q+v = 65,
c+h+1+r+w = 65,
d+i+n+s+x = 65,
e+j+o+t+y = 65,
u+q+1+i+e = 65,
a+g+1+s+y = 65}
) {
console.log(a,b,c,d,e,f,g,h,i,j,k,l,n,o,p,q,r,s,t,u,v,w,x,y);
found = true;
}
counter++;
}
However the obvious problem with this is that it's just randomly selecting values. So it will take an incredible amount of time. I can't work out how to iterate over every possible combination (without having 25 for loops) so I can check which values will pass the condition.
Given a range of numbers (1-25) how can I create a loop so that at each iteration I get a unique set of variables.
It sounds like you are talking about the permutations of a set. You can find a bunch of different algorithms to do this. Here is a nice one from this StackOverflow answer:
function getArrayMutations(arr, perms = [], len = arr.length) {
if (len === 1) perms.push(arr.slice(0))
for (let i = 0; i < len; i++) {
getArrayMutations(arr, perms, len - 1)
len % 2 // parity dependent adjacent elements swap
? [arr[0], arr[len - 1]] = [arr[len - 1], arr[0]]
: [arr[i], arr[len - 1]] = [arr[len - 1], arr[i]]
}
return perms
}
getArrayMutations([1, 2, 3])
> [ [ 1, 2, 3 ],
[ 2, 1, 3 ],
[ 3, 1, 2 ],
[ 1, 3, 2 ],
[ 2, 3, 1 ],
[ 3, 2, 1 ] ]
Be careful though! Permutations are factorial which means they grow really fast.
P(n, k) =
This means that if you want to permute 25 numbers, you are looking at 1.551121e+25 possible combinations which is getting into the not-computable-in-your-lifetime territory.
What I am trying to do is iterate over every possible number for each position (think sudoku) so in a 3x3 grid: a = top left position, b = top middle, etc...
Two dimensional arrays (really just lists of lists) are a great way to store matrix data like this. It doesn't fundamentally change the math to change the representation from a single array, but it might be easier to think about. I'm not 100% sure if you want a 3x3 grid or a 5x5 grid but I'll assume 5x5 since you have 25 numbers in your example. You can easily reshape them like this:
function reshapeArray(array, n=5) {
let result = []
let row = 0
let col = 0
for (let i = 0; i < array.length; i++) {
if (col == 0) {
result[row] = []
}
result[row][col] = array[i]
col++
if (col == n) {
col = 0
row++
}
}
return result
}
reshapeArray([1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25])
> [ [ 1, 2, 3, 4, 5 ],
[ 6, 7, 8, 9, 10 ],
[ 11, 12, 13, 14, 15 ],
[ 16, 17, 18, 19, 20 ],
[ 21, 22, 23, 24, 25 ] ]
so similar to sudoku I would have a condition (each row = 65: a + b + c + d + e= 65)
Now that you have your data in an iteratable array, you can very easily check this or any other constraint. For example:
/**
* Checks if a matrix (a 2-d array like the output from reshapeArray())
* meets our criteria.
*/
function checkMatrix(matrix) {
for (let row = 0; row < matrix.length; row++) {
let rowSum = 0
for (let col = 0; col < matrix[row].length; col++) {
rowSum += matrix[row][col]
}
// The row sum does not equal 65, so this isn't the one!
if (rowSum != 65) {
return false
}
}
// All the row sums equal 65
return true
}
If you want add extra rules (like having the columns sum to 65 as well) just modify the code to check for that. You can get the value at any point in the matrix by indexing it matrix[row][col] so matrix[0][0] is the upper-left, etc.
However the obvious problem with this is that it's just randomly selecting values. So it will take an incredible amount of time. I can't work out how to iterate over every possible combination (without having 25 for loops) so I can check which values will pass the condition.
Yes, it will. Sudoku is an NP-Hard problem. If you haven't seen complexity classes before, that's just a very mathematically formal way of saying that there's no clever solution that's going to be significantly faster than just checking every possible solution. This hypothetical problem is not exactly the same, so it might be possible, but it has a very np-ish feel to it.
Currently, your pseudocode solution would look like this:
let permutations = getPermutations() // You're going to need to change this part
// because getting all the permutations
// ahead of time will take too long.
// Just picking random numbers each time is
// not actually a terrible idea. Or, look at
// generator functions (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators)
for (let permutation of permutations) {
let matrix = reshapeArray(permutation)
if (checkMatrix(matrix)) {
console.log("Found it")
console.log(matrix)
break
}
}
If there is only one possible solution that matches your criteria, you will never find it this way. If there is a relatively high density of solutions, you will probably find some. If you really want to solve this problem I would recommend first looking at it from a mathematical perspective -- can you prove that it is or isn't NP? can you make some prediction about the density of solutions?
Not sure what the question really is. I would store the range in an Array:
function range(start, stop = null, upperCase = false){
let b = start, e = stop, s = 'abcdefghijklmnopqrstuvwxyz', x;
const a = [], z = s.split(''), Z = s.toUpperCase().split('');
if(typeof b === 'string'){
s = z.indexOf(b.toLowerCase());
if(e === null){
x = z.length;
}
else{
x = z.indexOf(e.toLowerCase())+1;
}
if(upperCase){
return Z.slice(s, x);
}
return z.slice(s, x);
}
else if(e === null){
e = b; b = 1;
}
for(let i=b; i<=e; i++){
a.push(i);
}
return a;
}
function permuCount(array){
let c = 1;
for(let i=0,n=1,l=array.length; i<l; i++,n++){
c *= n;
}
return c;
}
function comboCount(array){
let l = array.length;
return Math.pow(l, l);
}
console.log(range(2, 23)); console.log(range(10)); console.log(range('d'));
console.log(range('g', 'p')); console.log(range('c', 'j', true));
// here is where you'll have an issue
const testArray = range(0, 9);
console.log(permuCount(testArray));
console.log(comboCount(testArray));
As you can see there are way too many combinations. Also, you should have already see the following post: Permutations in JavaScript?
I am working on a challenge and in need of some help:
Write a for loop that calculates sum of squares of items in an array of numbers. Example: For array [ 1, 2, 3, 4 ] it calculates the sum of squares as 30 (i.e. 1 + 4 + 9 + 16). I have a fiddle set up if anyone wants to have a closer look. Thanks for your help!
https://jsfiddle.net/jamie_shearman/2drt56e3/23/
var aFewNumbers = [ 1, 2, 3, 7 ];
var squareOfAFewNumbers = 0;
for( var i = 0; i <= aFewNumbers; i++ ) {
squareOfAFewNumbers = squareOfAFewNumbers * aFewNumbers[i] ;
}
console.log( squareOfAFewNumbers );
Your math is wrong. As an obvious issue, the variable starts at 0 and then is multiplied by each array element; 0 times anything is 0, so it will always remain 0 no matter what the values are. Not to mention your loop isn't looking at the length of the array as a stopping condition, which it should be, since you want to iterate from the beginning to the end of the array.
You need to iterate through to the array's length, square each array element, and add that square to the variable:
for( var i = 0; i < aFewNumbers.length; i++ ) {
squareOfAFewNumbers += aFewNumbers[i] * aFewNumbers[i];
}
If you can use ES6, you can even use higher-order array functions to simplify this more:
var squareOfAFewNumbers = aFewNumbers.reduce((result, entry) => result + entry * entry, 0);
There are multiple approaches you can take for reaching the desired result, but as you've mentioned that you must write a for loop; therefore, I sorted the answers by having that in mind.
Using the for loop
let numbers = [1, 2, 3, 7],
sum = 0;
for(let i = 0; i < numbers.length; i++) {
sum += Math.pow(numbers[i], 2)
}
// Sum is now 63
Using forEach method of the array object
let numbers = [1, 2, 3, 7],
sum = 0;
numbers.forEach(number => sum += Math.pow(number, 2))
// Sum is now 63
Oneliner
let sum = [1, 2, 3, 7].reduce((a, c) => a + Math.pow(c, 2))
The reduce method uses an accumulator to store temporary results, the accumulator is passed to the callback as the first argument and the second argument is the element's value, you can read more about the reduce method here.
You can use JavaScript pow() Method to create the square and sum it to the sumSquareOfAFewNumbers.
var aFewNumbers = [ 1, 2, 3, 7 ];
var sumSquareOfAFewNumbers = 0;
aFewNumbers.forEach(function(element) {
sumSquareOfAFewNumbers += Math.pow(element, 2);
});
console.log(sumSquareOfAFewNumbers)
I've noticed my algorithm solutions often include ugly nested for loops when better options are available. In the example below, how can I determine the prime numbers up to the given parameter without nested loops? One constraint of the assignment was to not utilize any external functions.
function sumPrimes(num) {
var p = [];
for (var i = 2; i <= num; i++)
{
p.push(i);
for (var j = 2; j < i; j++)
{
if (i % j === 0) //not a prime
{
p.pop(i);
break;
}
}
}
return p;
I don't know if there is any other good solution but I came up with this. There is still one for loop ;)
function primes(num) {
return Array.apply(null, {length: (num + 1)}).map(Number.call, Number)
.filter(function(n) {
for(var i = 2; i < n; i++) {
if(n % i === 0) return false;
}
return n !== 0 && n !== 1;
})
}
Explanation:
Array.apply(null, {length: (num + 1)}).map(Number.call, Number)
This line creates an Array with the range of the passed argument. If num would be 5 it would create the following Array: [0, 1, 2, 3, 4, 5]. I found this here.
Then I use the filter function to remove all non prime numbers. If the filter function returns false the number will be removed from the array. So inside the filter function we check if the current number is a prime number. If so, true is returned. As you can see I still use a normal for loop here.
No you can call the function as follows: primes(28);
This will return the following Array: [ 2, 3, 5, 7, 11, 13, 17, 19, 23 ]
In this specific case I would say to use normal for loops is absolutely ok. But always consider functions like map, reduce or filter when you operate on arrays.
This is easy to mis-explain so I'll simplify it. Let's say I have an array that are the results of dice throws. Like:
1 2 4 6 1 2 6 6 2 4 etc
Every time you throw a 6, you win. I want to create a new array which contains after how many turns you would win based on the original array. So the above array would create an array that is:
4 3 1
(it takes 4 turns to win, then 3, then 1)
So I only want to count the distance between the 6's. (I could also convert the dice results to binary win/lose)
How do I do this in excel? (or javascript, but really prefer excel)
Create a Helper Column (Column A of Excel). Put 1 in the first cell (A2) of Helper column. Follow it up with the formula (in A3) =IF(B3=6,A2+1,A2).Drag it to the last row of to the given array.
Then Create a Result column (Column C of Excel). Type in formula (in C2)
=IF(ROW()-1=MAX(A:A),"",IF(IF(ROW()-1=1,COUNTIF(A:A,ROW()-1)+1,COUNTIF(A:A,ROW()-1))=0,"",IF(ROW()-1=1,COUNTIF(A:A,ROW()-1)+1,COUNTIF(A:A,ROW()-1))))
in the first cell of Result Column (Column C of Excel). Drag and get the required result.
Hide Helper Column.
Note: Array Data starts from cell B2
If the first array is B1:K1 the second might be created with:
=IF(B1=6,COLUMN()-SUM(A2:$B2)-1,"")
in B2 and copied across to suit.
This might work for you:
var rollsUntil6 = function(rolls) {
return rolls.reduce(function(indices, roll, idx) {
if (roll == 6) {indices.push(idx);} return indices;
}, [-1]).map(function(val, idx, arr) {
return val - arr[idx - 1];
}).slice(1);
};
rollsUntil6([1, 2, 4, 6, 1, 2, 6, 6, 2, 4]); //=> [4, 3, 1]
What you need to do is iterate over the array and count the spaces by accumulating into a collector variable. You can find the code below it just pops into and alert window.(Javascript)
var array = [1, 2, 4, 6, 1, 2, 6, 6, 2, 4]
var resultArray = []
var i = 0;
var distance = 0;
for (i = 0; i < array.length; i++) {
distance++;
if (array[i] == 6) {
resultArray.push(distance);
distance = 0;
}
}
alert(resultArray);
I took an attempt at doing in excel.
You can place a command button and define a sub function like below and you will get the results expected. For instructions on how to place a command button http://www.excel-easy.com/vba/create-a-macro.html#command-button
Sub DistanceOf6InString(x As String)
Size = Len(x)
distance = 0
result = ""
Dim i As Integer
For i = 1 To Size
distance = distance + 1
If (Mid(x, i, 1) = "6") Then
result = result & distance
distance = 0
End If
Next i
MsgBox result
End Sub
Private Sub CommandButton1_Click()
DistanceOf6InString ("1246126624")
End Sub
You can repeatedly find the array.indexOf(6,lastmatch)
var array= [1, 2, 4, 6, 1, 2, 6, 6, 2, 4];
var resultArray= [], i, incr= 0;
while((i= array.indexOf(6, incr))!= -1){
i+= 1;
resultArray.push(i-incr);
incr= i;
}
resultArray returned value: (Array) [4,3,1]