code: def balance_data(episodes: List[Tuple]) -> List[Tuple]:
      """
      Balance the data so that we have equal numbers of memory/no memory.
  
      Very hacky and requires deep understanding of DialogData objects.
  
      Should in theory be used in a script to dump to disk.
      """
      random.seed(42)
      pos_inds = set()
      neg_inds = set()
      for i, ep in enumerate(episodes):
          # assume flattened
          assert len(ep) == 1
          ex = ep[0]
          label = ex[1][0] if isinstance(ex[1], list) else ex[1]
          if label == BB3_CONST.DO_ACCESS_MEMORY:
              pos_inds.add(i)
          elif label == BB3_CONST.DONT_ACCESS_MEMORY:
              neg_inds.add(i)
          else:
              raise ValueError(f"Incorrect label: {label}")
      pos_exs = [e for i, e in enumerate(episodes) if i in pos_inds]
      neg_exs = [e for i, e in enumerate(episodes) if i in neg_inds]
      new_data = []
      num_to_sample = min(len(pos_exs), len(neg_exs))
      if num_to_sample == len(pos_exs):
          new_data = pos_exs + random.sample(neg_exs, num_to_sample)
      else:
          new_data = neg_exs + random.sample(pos_exs, num_to_sample)
  
      return new_data
  
imports: import random
  from typing import List, Tuple
  from parlai.core.opt import Opt
  import parlai.tasks.convai2.agents
  import parlai.tasks.blended_skill_talk.agents
  import parlai.tasks.empathetic_dialogues.agents
  import parlai.tasks.msc.agents
  import parlai.tasks.wizard_of_wikipedia.agents
  import parlai.utils.logging
  import projects.bb3.constants
  from projects.bb3.tasks.module_level_tasks import BB3TeacherMixin
  from projects.seeker.tasks.search_decision import WoiSearchDecisionTeacher, SquadSearchDecisionTeacher, TriviaQASearchDecisionTeacher, NQSearchDecisionTeacher, Convai2SearchDecisionTeacher, EDSearchDecisionTeacher, MSCSearchDecisionTeacher
label_desc: Use image node_id 2 for calling a global function with example usage: balance_data(episodes) and returns: new_data