Каждый с каждым
Допустим есть класс
class Team {
}
и мне нужно каким-либо образом обыграть это так, чтобы каждая команда из имеющегося у меня List<Team> (команда A, команда B, команда C, команда D) сражалась против другой команды (то есть A играют с B, потом с C, пока B играют с D), но при этом они не повторялись. Как правильно реализовать это в Java?
Ответы (3 шт):
Не уверен как правильно, может есть более легкий способ. Но сразу в голову приходит воспользоваться коллекцией hashmap. Потому что это всегда очень быстрое и довольно универсальное решение. Код с объяснениями ниже:
public class Test {
public static void main(String[] args) {
List<Team> list = new ArrayList<>();
list.add(new Team("A"));
list.add(new Team("B"));
list.add(new Team("C"));
list.add(new Team("D"));
list.add(new Team("G"));
play(list);
}
public static void play(List<Team>list){
Map<Team, List<Team>> alreadyPlayed = new HashMap<>();
//инициализация хэшмепа: команда: список команд, с которыми уже сыграла данная команда
for(int i=0;i<list.size();i++)
alreadyPlayed.put(list.get(i), new ArrayList<>());
for(int i=0;i<list.size();i++)
for(int j=0;j<list.size();j++)
{
if
((!list.get(i).equals(list.get(j))) // проверка чтобы команда А не играла с командой А
&&
(!alreadyPlayed.get(list.get(i)).contains(list.get(j))) // проверка что команды еще не играли между собой
)
{
alreadyPlayed.get(list.get(i)).add(list.get(j));
alreadyPlayed.get(list.get(j)).add(list.get(i));
//добавление в хэшмеп инофрмации что команды между собой сыграли
System.out.println(list.get(i)+" plays with "+list.get(j));
//собственно игра
}
}
}
}
class Team {
String name;
public Team(String name) {
this.name = name;
}
@Override
public String toString() {
return "Team " + name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Team team = (Team) o;
return Objects.equals(name, team.name);
}
}
Вывод консоль:
Team A plays with Team B
Team A plays with Team C
Team A plays with Team D
Team A plays with Team G
Team B plays with Team C
Team B plays with Team D
Team B plays with Team G
Team C plays with Team D
Team C plays with Team G
Team D plays with Team G
Process finished with exit code 0
Чтобы игры не повторялись - логично воспользоваться коллекцией, которая самостоятельно отсекает повторения: Set
Собственно, "игра" в контексте задачи - это комбинация 2 команд. Единственное, что требуется - это обеспечить уникальность вне зависимости от расположения этих команд в игре. Для этого (дабы Set мог правильно отсекать дубликаты) следует перекрыть базовые методы equals() и hashCode():
private record Team(String name) {
}
private record Game(Team team1, Team team2) {
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Game game = (Game) o;
return (team1.equals(game.team1) && team2.equals(game.team2))
|| (team1.equals(game.team2) && team2.equals(game.team1));
}
@Override
public int hashCode() {
if (team1.name.compareTo(team2.name) >= 0)
return Objects.hash(team1, team2);
else
return Objects.hash(team2, team1);
}
@Override
public String toString() {
return "Game{" +
"team1=" + team1 +
", team2=" + team2 +
'}';
}
}
И теперь остается только создать все возможные комбинации игр и добавить их в Set, который самостоятельно отсечет дубликаты, основываясь на перекрытых методах:
public static void main(String[] args) {
List<Team> teams = IntStream.range(1, 5)
.boxed()
.map(i -> new Team(i.toString()))
.toList();
Set<Game> games = teams.stream()
.flatMap(team -> teams.stream().map(team1 -> new Game(team, team1)))
.collect(Collectors.toUnmodifiableSet());
games.forEach(
game -> System.out.println(game.toString())
);
}
Максимально простой (тривиальный) способ:
Два вложенных цикла, первый (по индексу i) идет от первого до последнего элемента, вложенный (по индексу j) идет от следующего элемента (от i + 1) до последнего - тогда изначально не будет игр "сам с собой" и обратных повторений, и никакие "дубликаты" не нужно будет удалять.
public static void main(String[] args) {
List<String> items = List.of("Команда 1", "Команда 2", "Команда 3", "Команда 4", "Команда 5");
for (int i = 0; i < items.size(); i++) {
for (int j = i + 1; j < items.size(); j++) {
System.out.printf("%s играет с %s\n", items.get(i), items.get(j));
}
}
}
Вывод:
Команда 1 играет с Команда 2
Команда 1 играет с Команда 3
Команда 1 играет с Команда 4
Команда 1 играет с Команда 5
Команда 2 играет с Команда 3
Команда 2 играет с Команда 4
Команда 2 играет с Команда 5
Команда 3 играет с Команда 4
Команда 3 играет с Команда 5
Команда 4 играет с Команда 5