0

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.

Aequitas
  • 1,875
  • 1
  • 19
  • 43
  • I'm not sure I'm following exactly what you want to do but I would really recommend against using variable in that way. If you use an array instead it would be much easier to iterate over and will be much more resilliant to change later on – QuinnFreedman Feb 27 '20 at 02:27
  • @B1CL0PS hi, thanks for your suggestion, what am I failing to explain properly with what I want to do? thank you – Aequitas Feb 27 '20 at 02:28
  • Matrix is made for that, you have a 12x6 matrix and every number row is equal to 65, Linear algebra should have an easy solution for this, can't remember right know how to translate that to code. – Sxntk Feb 27 '20 at 03:07
  • 1
    @Aequitas I posted a pretty long answer. I think after reading a second time I get the gist of what you wanted. Hopefully it is helpful – QuinnFreedman Feb 27 '20 at 06:56

2 Answers2

1

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?

QuinnFreedman
  • 1,664
  • 2
  • 19
  • 34
0

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?

StackSlave
  • 10,198
  • 2
  • 15
  • 30
  • No this isn't quite what I meant. I will update question with additional information in a moment – Aequitas Feb 27 '20 at 02:16
  • A unique set of variables? I'm sure you want an Array. If you are dealing with large array and you want to get all the combinations, that could take a while. – StackSlave Feb 27 '20 at 03:07