Yonah Karp
Yonah Karp

Reputation: 671

Array within an Array (2D Array?)

The title probably isn't clear and I'm not sure how to articulate the idea without specifics so here's the rundown:

My code has an array of Players (a class I wrote). I want to split the entries in the array evenly (based on their Players.rating) between a given number of teams. The problem arises that the number of teams is a var teamAmount and can be set between 2 and 8. I'm trying to find a simple way of creating a number of Player class arrays equal to the value of teamAmount (without having to write 7 switch cases). I was thinking a 2D array, but I can't think of how to initialize it. I feel like it could be simple, but I can't seem to work it out

Upvotes: 3

Views: 87

Answers (2)

fqdn
fqdn

Reputation: 2843

here is an option for you:

// e.g. setting up Player(s)
struct Player {
  var rating = 0
}
let players = [Player(rating: 1), Player(rating: 3), Player(rating: 2), Player(rating: 7), Player(rating: 5), Player(rating: 4), Player(rating: 3)]
let sortedPlayers = players.sort { $0.rating > $1.rating }

print(sortedPlayers)
// [Player(rating: 7), Player(rating: 5), Player(rating: 4), Player(rating: 3), Player(rating: 3), Player(rating: 2), Player(rating: 1)]

// e.g. setting up Team(s)
let numberOfTeams = 3
typealias Team = [Player]

// now do the work
let teams = sortedPlayers.enumerate().reduce(
  Array(count: numberOfTeams, repeatedValue: Team()),
  combine: { (var teams, let player) in
    let (playerIndex, player) = player
    teams[playerIndex % numberOfTeams].append(player)
    return teams
  }
)

print(teams)
// [[Player(rating: 7), Player(rating: 3), Player(rating: 1)], [Player(rating: 5), Player(rating: 3)], [Player(rating: 4), Player(rating: 2)]]

Upvotes: 1

Unome
Unome

Reputation: 6900

I've posted some pseudo-code below. You'll have to modify it to fit the Swift syntax (I'm away form a Mac at the moment and will edit this when I get home after I throw it in a playground.)

func generate2DArray(players: Array<Player>, numTeams: Int) -> Array<Array<String>>{
  var teams = Array<Array<Player>>()

  for index in 0...numTeams{
      //init the first dimension of empty arrays for each team
      teams.append([Player]())
  }

  for var i = 0; i < players.count; ++i{
    //Place the player in the correct team respectively... (sorry about array syntax, I know its wrong)
      teams[i % numTeams].append(players[i]);
  }
  return teams;
}

The basic idea is you know how many teams you want and you can init the first dimension of your 2D array with a simple for loop.

Then to place the players in the respective teams, just use the magical modulus.

Theory

  • Player 1 % 4 Teams = Belongs on team 1.
  • Player 2 % 4 Teams = Belongs on team 2
  • Player 3 % 4 Teams = Belongs on team 3.
  • Player 4 % 4 Teams = Belongs on team 0.
  • Player 5 % 4 Teams = Belongs on team 1.
  • Player 6 % 4 Teams = Belongs on team 2.
  • Player 7 % 4 Teams = Belongs on team 3.
  • Player 8 % 4 Teams = Belongs on team 0.

(Since 4 % 4 is 0, you will have to offset your array, or provide some simple logic to cover that case, the easiest would be to have a team 0 instead of team 4)

Update

Just noticed you want them distributed evenly by the players rating. In that case, just make sure you sort the players by their rating before placing them into teams (I'll omit showing how to do that under the assumption that you know how to sort an array in Swift, comment if help is needed.)

Update

I tested the code I added and made some modifications so that it runs properly in Swift

Here are the results as expected

generate2DArray([player1, player2, player3, player4, player5, player6], 2)
//Returns [player1, player3, player5] , [player2, player4, player6]
generate2DArray([player1, player2, player3, player4, player5, player6], 4)
//Returns [player1, player5] , [player2, player6] , [player3] , [player4]

Upvotes: 1

Related Questions