Home > OS >  Make formation of array into multiple arrays with having minimum items - JavaScript
Make formation of array into multiple arrays with having minimum items - JavaScript

Time:10-05

I have an array of teams, I am trying to split that array into multiple arrays with having minimum players in each array. I mean, form the array into multiple teams from array. I forgot what this feature is called, but let me tell you with an explanation:

minimum players: 3
team array: [4, 6, 5, 8]

This array will form like this:

[
  [4, 6, 5],
  [4, 6, 8],
  [4, 5, 8],
  [6, 5, 8],
  [4, 6, 5, 8]
]

So, I have tried doing this problem, but I got stuck that what to do and how to do.

function teams(minPlayers, arr) {
    for (let i = 0; i < arr.length; i  ) {
        const subArray = []
        let startMax = minPlayers - 2
        let end = minPlayers
        for (let j = 0; j < arr.length; j  ) {
            if (j < startMax) {
                subArray[i] = arr[i]
            }
        }
    }
}
console.log(teams(3, [4, 6, 5, 10]))

It will be a pleasure if you help me.

CodePudding user response:

Here is a generator that generates the combinations through recursion. Array.from will consume the iterator:

function teams(minPlayers, arr) {
    // Execute a generator, and pass it to Array.from to turn its
    //  yielded values into an array and return it
    return Array.from(function* iter(minPlayers, start) {
        // When there are as many remaining elements (from start)
        //   as we need players, then there are no other options 
        //   than selecting all those values, so yield that slice of
        //   the array and return (base case)
        if (arr.length - minPlayers == start) return yield arr.slice(start);
        // Produce the cases where the element at start is not selected.
        //   Use recursion for this, by reducing the slice that is still available
        yield* iter(minPlayers, start   1);
        // Produce the cases where the element at start is selected.
        //   Use recursion to get the combinations after that, and 
        //   prefix the start element to each of those
        for (let combi of iter((minPlayers || 1) - 1, start   1)) {
            yield  [arr[start], ...combi];
        }
    }(minPlayers, 0)); // Immediately execute the generator function
}
console.log(teams(3, [4, 6, 5, 10]));

So the idea of the generator is to either take the current value or not (current is arr[start]). In either case, defer the other selections to recursion. The recursive call will get an increased start value so there are fewer elements to choose from.

CodePudding user response:

This is not exactly permutation quite the opposite since we don't care for order, but we do care for picking n different items.

The recursive function picks works by picking an item (length times) then running picks on the rest - concatenating the results. A care is given not to pick numbers that are "left" to the position of our current item position since we already counted them.

// this loops over minPlayers to maxPlayers (length)
function teams(minPlayers, arr) {
  var result = [];
  for (var i = minPlayers; i <= arr.length; i  ) {
    result = result.concat(picks(i, arr))
  }
  return result;
}

// picks all possible n items from arr (hopefully)
function picks(n, arr) {

  // will hold all possible series (pick of n items from array)
  var result = [];

  if (n == 1) {
  
    // base case return n arrays of 1 item
    for (var i = 0; i < arr.length; i  ) {
      result.push([arr[i]])
    }
    return result;
  }

  // else we will loop over each of items
  for (var i = 0; i < arr.length; i  ) {
  
    // make a copy since we are going to remove items from it
    var copy = [...arr];
    
    // pick an item, the first one of our series
    var item = copy.splice(i, 1);
    
    // ignore those before it
    for (j = 0; j < i; j  ) {
    
      // remove an item from beginning of array
      copy.shift();
    }
    
    // recursion! get picks of the rest n-1 items
    var others = picks(n - 1, copy);
    
    // combine each pf those picks with our item
    others.forEach(function(other) {
    
      // push to result the series which is [item, ...rest]
      result.push(item.concat(other))
    })
  }
  
  // return array of arrays
  return result;
}

console.log(teams(3, [4, 6, 5, 10]))
.as-console-wrapper {
  max-height: 100% !important;
}

Last function can be refactored a little since base case looks similar to the other steps and no need to mutate the array. Here's the shorter version:

// loop for each possible minPlayers and above
function teams(minPlayers, arr) {
  var result = [];
  for (var i = minPlayers; i <= arr.length; i  ) {
    result = result.concat(picks(i, arr))
  }
  return result;
}

// recursive function to pick all possible n items from arr
function picks(n, arr) {

  var result = [];

  for (var i = 0; i < arr.length; i  ) {
  
    // foreach item
    var item = arr[i];
    
    if (n == 1) {
    
      // if we need pick 1, then pick item
      result.push([item])
    } else {
    
      // pick n-1 possible except our item (and those before it)
      var others = picks(n - 1, arr.slice(i   1));
      
      // combine with our item n times
      others.forEach(function(other) {
        result.push([item, ...other])
      })
    }
  }

  return result;
}

console.log(teams(3, [4, 6, 5, 10]))
.as-console-wrapper {
  max-height: 100% !important;
}

  • Related