from typing import Mapping
from typing import Any
from typing import Tuple
from typing import List
from typing import Union


def flatten_dict(
    d: Mapping[str, Any], prefix: Tuple[str, ...] = ()
) -> List[Tuple[str, Union[int, float, str]]]:
  """Returns a sequence of flattened (k, v) pairs for tfsummary.hparams().

  Args:
    d: A dict-like object that has an `.item()` method.
    prefix: Prefix to add to keys in `d`.

  Returns:
    Sequence of (k, v) pairs where k is the flattened key with individual
    subkeys separated by dots. `None` values are replaced by the empty string.
  """
  ret = []
  for k, v in d.items():
    # Note `ml_collections.ConfigDict` is not (yet) a `Mapping`.
    if isinstance(v, Mapping) or hasattr(v, "items"):
      ret += flatten_dict(v, prefix + (k,))
    elif isinstance(v, (list, tuple)):
      ret += flatten_dict({str(idx): value for idx, value in enumerate(v)},
                          prefix + (k,))
    else:
      ret.append((".".join(prefix + (k,)), v if v is not None else ""))
  return ret