title: What is the best approach to solve a N to N relationship algorithm problem?
body: <p>I'm trying to write an algorithm to organize the schedule of N rooms to N professionals. I have a List of Room objects and another List of professionals. The idea is to be able to assign a professional to a specific room for the day. The twist here is that the professional can be of kind &quot;specialty&quot; (represented by a boolean attribute). This professional requires a special kind of room. Rooms have an attribute isSpecialtyRoom. Ideally, the algorithm would try to match specialty rooms with specialty professionals first, but if an room is vacant it's ok to booked it with a regular professional.</p>
  <p>This code is what I've been working on, but I'm getting exceptions everytime. I wonder what would be the best approach to solve a problem like this?</p>
  <pre><code>private List&lt;Room&gt; generateDailySchedule(List&lt;Room&gt; roomList, List&lt;Professional&gt; professionalList) {
      if (roomList.size() &lt;= 0 || professionalList.size() &lt;=0) return roomList;
  
      //first run to find matches.
      int pIndex = 0;
    
      for (Room room : roomList) {
          if (pIndex &lt; professionalList.size()) {
              if ((!room.isSpecialtyRoom() &amp;&amp; !professionalList.get(pIndex).isRequiresSpecialtyRoom()) ||
                      (room.isSpecialtyRoom() &amp;&amp; professionalList.get(pIndex).isRequiresSpecialtyRoom())) {
                  room.setProfessional(professionalList.get(pIndex));
                  professionalList.get(pIndex).setRoom(room);
              
                  pIndex++;
              }
          }
      }
     
      //search for remaining professionals
      List&lt;Professional&gt; professionalsWaitingList = professionalList.stream()
              .filter(professional -&gt; professional.getRoom() == null).collect(Collectors.toList());
     
      //search for remaining empty rooms
      List&lt;Room&gt; vacantRooms = roomList.stream().filter(room -&gt; room.getProfessional() == null).collect(Collectors.toList());
  
      if (vacantRooms.size() &gt; 0 &amp;&amp; professionalsWaitingList.size() &gt; 0) {
          for (Room vacantRoom : vacantRooms) {
              if (!vacantRoom.isSpecialtyRoom()) {
                  vacantRoom.setProfessional(professionalsWaitingList.stream().findFirst().get());
              } else {
                  Optional&lt;Professional&gt; specialtyProfessional = professionalsWaitingList.stream()
                          .filter(professional -&gt; (professional.isRequiresSpecialtyRoom() &amp;&amp; professional.getRoom() == null))
                          .findFirst();
                  if (specialtyProfessional.isPresent()) {
                      vacantRoom.setProfessional(specialtyProfessional.get());
                      specialtyProfessional.get().setRoom(vacantRoom);
                  } else {
                      System.out.println(&quot;No specialty professional found for room &quot; + vacantRoom.getRoomName());
                      Optional&lt;Professional&gt; anyProfessional = professionalsWaitingList.stream()
                              .filter(professional -&gt; professional.getRoom() == null)
                              .findFirst();
                      if(anyProfessional.isPresent()) {
                          vacantRoom.setProfessional(anyProfessional.get());
                          anyProfessional.get().setRoom(vacantRoom);
                      } else {
                          System.out.println(&quot;No professional found for room &quot; + vacantRoom.getRoomName());
                      }
                  }
              }
          }
      }
      return roomList;
  }
  </code></pre>
  <p>This is the simplified version of the code for the Professional and Room Models:</p>
  <pre><code>@Entity
  public class Professional {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  @NotNull
  private String name;
  
  @OneToOne(cascade = CascadeType.ALL)
  @JoinTable( name = &quot;professional_room&quot;,
      joinColumns = { @JoinColumn(name = &quot;professional_id&quot;, referencedColumnName = &quot;id&quot;) },
      inverseJoinColumns = { @JoinColumn(name = &quot;room_id&quot;, referencedColumnName = &quot;id&quot;) })
  private Room room;
  
  private Boolean requiresSpecialtyRoom;
  </code></pre>
  <ul>
  <li></li>
  </ul>
  <pre><code>@Entity
  public class Room {
  
  @Id
  @GeneratedValue(strategy = GenerationType.IDENTITY)
  private Long id;
  
  @NotBlank
  private String roomName;
  
  @NotNull
  private boolean specialtyRoom;
  
  @OneToOne(mappedBy = &quot;room&quot;)
  private Professional professional;
  </code></pre>