code: def _extract_actions_unique_topics(self, movement_counts, max_movements, cluster_topology, max_movement_size):
          
          # Group actions by topic
          topic_actions = defaultdict(list)
          for t_p, replica_change_cnt in movement_counts:
              topic_actions[t_p[0]].append((t_p, replica_change_cnt))
  
          # Create reduced assignment minimizing duplication of topics
          extracted_actions = []
          curr_movements = 0
          curr_size = 0
          action_available = True
          while curr_movements < max_movements and curr_size <= max_movement_size and action_available:
              action_available = False
              for topic, actions in six.iteritems(topic_actions):
                  for action in actions:
                      action_size = cluster_topology.partitions[action[0]].size
                      if curr_movements + action[1] > max_movements or curr_size + action_size > max_movement_size:
                          # Remove action since it won't be possible to use it
                          actions.remove(action)
                      else:
                          # Append (topic, partition) to the list of movements
                          action_available = True
                          extracted_actions.append(action[0])
                          curr_movements += action[1]
                          curr_size += action_size
                          actions.remove(action)
                          break
          return extracted_actions
docs: Extract actions limiting to given max value such that
             the resultant has the minimum possible number of duplicate topics.
  
             Algorithm:
             1. Group actions by by topic-name: {topic: action-list}
             2. Iterate through the dictionary in circular fashion and keep
                extracting actions with until max_partition_movements
                are reached.
             :param movement_counts: list of tuple ((topic, partition), movement count)
             :param max_movements: max number of movements to extract
             :param cluster_topology: cluster topology containing the new proposed assignment for the cluster
             :param max_movement_size: maximum size of data to move at a time in extracted actions
             :return: list of tuple (topic, partitions) to include in the reduced plan