class_docstr: Stores multi-agent episode data.
  
  The central attribute of the class is the timestep mapping
  `global_t_to_local_t` that maps the global (environment)
  timestep to the local (agent) timesteps.
  
  The `MultiAgentEpisode` is based on the `SingleAgentEpisode`s
  for each agent, stored in `MultiAgentEpisode.agent_episodes`.
class_docstr_tok: ["Stores","multi-agent","episode","data",".","The","central","attribute","of","the","class","is","the","timestep","mapping","`","global_t_to_local_t","`","that","maps","the","global","(","environment",")","timestep","to","the","local","(","agent",")","timesteps",".","The","`","MultiAgentEpisode","`","is","based","on","the","`","SingleAgentEpisode","`","s","for","each","agent",",","stored","in","`","MultiAgentEpisode.agent_episodes","`","."]
docstr: Returns values in the form of indices: [-1, -2].
code: def _getattr_by_index(
      self,
      attr: str = "observations",
      indices: Union[int, List[int]] = -1,
      key: Optional[str] = None,
      has_initial_value=False,
      global_ts: bool = True,
      global_ts_mapping: Optional[MultiAgentDict] = None,
      shift: int = 0,
      as_list: bool = False,
      buffered_values: MultiAgentDict = None,
  ) -> MultiAgentDict:
      """Returns values in the form of indices: [-1, -2]."""
      # TODO (simon): Does not give yet indices that are in between.
      # TODO (sven): Do we even need indices in between? This is very
      # tricky.
  
      if not global_ts_mapping:
          global_ts_mapping = self.global_t_to_local_t
  
      # First for global_ts = True:
      if global_ts:
          # Check, if the indices are iterable.
          if isinstance(indices, list):
              indices = [
                  (self.t + idx + int(has_initial_value))
                  if idx < 0
                  else idx + self.ts_carriage_return
                  for idx in indices
              ]
          # If not make them iterable.
          else:
              indices = (
                  [
                      self.t
                      # - self.ts_carriage_return
                      + indices
                      + int(has_initial_value)
                  ]
                  if indices < 0
                  # else [indices + 1]
                  else [indices + self.ts_carriage_return]
              )
  
          # If a list should be returned.
          if as_list:
              if buffered_values:
                  return [
                      {
                          agent_id: (
                              getattr(agent_eps, attr).get(key)
                              + buffered_values[agent_id]
                          )[
                              global_ts_mapping[agent_id].find_indices(
                                  [idx]
                              )[0]
                          ]
                          for agent_id, agent_eps in self.agent_episodes.items()
                          if global_ts_mapping[agent_id].find_indices(
                              [idx], shift
                          )
                      }
                      for idx in indices
                  ]
              else:
                  return [
                      {
                          agent_id: (getattr(agent_eps, attr))[
                              global_ts_mapping[agent_id].find_indices(
                                  [idx], shift
                              )[0]
                          ]
                          for agent_id, agent_eps in self.agent_episodes.items()
                          if global_ts_mapping[agent_id].find_indices(
                              [idx], shift
                          )
                      }
                      for idx in indices
                  ]
          # Otherwise we return a dictionary.
          else:
              if buffered_values:
                  # Note, for addition we have to ensure that both elements are lists
                  # and terminated/truncated agents have numpy arrays.
                  return {
                      agent_id: list(
                          map(
                              (
                                  getattr(agent_eps, attr).get(key)
                                  + buffered_values[agent_id]
                              ).__getitem__,
                              global_ts_mapping[agent_id].find_indices(
                                  indices, shift
                              ),
                          )
                      )
                      for agent_id, agent_eps in self.agent_episodes.items()
                      # Only include agent data for agents that stepped.
                      if global_ts_mapping[agent_id].find_indices(
                          indices, shift
                      )
                  }
              else:
                  return {
                      agent_id: list(
                          map(
                              getattr(agent_eps, attr).__getitem__,
                              global_ts_mapping[agent_id].find_indices(
                                  indices, shift
                              ),
                          )
                      )
                      for agent_id, agent_eps in self.agent_episodes.items()
                      # Only include agent data for agents that stepped.
                      if global_ts_mapping[agent_id].find_indices(
                          indices, shift
                      )
                  }
      # Otherwise just look for the timesteps in the `SingleAgentEpisode`s
      # directly.
      else:
          # Check, if the indices are iterable.
          if not isinstance(indices, list):
              indices = [indices]
  
          # If we have buffered values for the attribute we want to concatenate
          # while searching for the indices.
          if buffered_values:
              return {
                  agent_id: list(
                      map(
                          (
                              getattr(agent_eps, attr).get(key)
                              + buffered_values[agent_id]
                          ).__getitem__,
                          set(indices).intersection(
                              set(
                                  range(
                                      -len(global_ts_mapping[agent_id]),
                                      len(global_ts_mapping[agent_id]),
                                  )
                              )
                          ),
                      )
                  )
                  for agent_id, agent_eps in self.agent_episodes.items()
                  if set(indices).intersection(
                      set(
                          range(
                              -len(global_ts_mapping[agent_id]),
                              len(global_ts_mapping[agent_id]),
                          )
                      )
                  )
              }
          else:
              return {
                  agent_id: list(
                      map(
                          getattr(agent_eps, attr).__getitem__,
                          set(indices).intersection(
                              set(
                                  range(
                                      -len(global_ts_mapping[agent_id]),
                                      len(global_ts_mapping[agent_id]),
                                  )
                              )
                          ),
                      )
                  )
                  for agent_id, agent_eps in self.agent_episodes.items()
                  if set(indices).intersection(
                      set(
                          range(
                              -len(global_ts_mapping[agent_id]),
                              len(global_ts_mapping[agent_id]),
                          )
                      )
                  )
              }
  
imports: from collections import defaultdict
  from queue import Queue
  from typing import Any, Dict, List, Optional, Set, Union
  import uuid
  import numpy
  from ray.rllib.env.single_agent_episode import SingleAgentEpisode
  from ray.rllib.policy.sample_batch import MultiAgentBatch
  from ray.rllib.utils.typing import MultiAgentDict
label_desc: Use image node_id 24 for calling the MultiAgentEpisode obj's underlying member method code with example usage: obj._getattr_by_index(attr, indices, key, has_initial_value, global_ts, global_ts_mapping, shift, as_list, buffered_values) and returns: unknown, unknown, unknown, unknown, unknown, unknown