flattening a dict

Collapse
This topic is closed.
X
X
 
  • Time
  • Show
Clear All
new posts
  • Benjamin

    flattening a dict

    How would I go about "flattening " a dict with many nested dicts
    within? The dicts might look like this:
    {"mays" : {"eggs" : "spam"},
    "jam" : {"soda" : {"love" : "dump"}},
    "lamba" : 23
    }
    I'd like it to put "/" inbetween the dicts to make it a one
    dimensional dict and look like this:
    {"mays/eggs" : "spam",
    "jam/soda/love" : "dump",
    "lamba" : 23
    }
  • Jeff Schwab

    #2
    Re: flattening a dict

    Benjamin wrote:
    How would I go about "flattening " a dict with many nested dicts
    within? The dicts might look like this:
    {"mays" : {"eggs" : "spam"},
    "jam" : {"soda" : {"love" : "dump"}},
    "lamba" : 23
    }
    I'd like it to put "/" inbetween the dicts to make it a one
    dimensional dict and look like this:
    {"mays/eggs" : "spam",
    "jam/soda/love" : "dump",
    "lamba" : 23
    }
    What have you tried so far?

    Comment

    • Arnaud Delobelle

      #3
      Re: flattening a dict

      On Feb 17, 3:56 am, Benjamin <musiccomposit. ..@gmail.comwro te:
      How would I go about "flattening " a dict with many nested dicts
      within? The dicts might look like this:
      {"mays" : {"eggs" : "spam"},
      "jam" : {"soda" : {"love" : "dump"}},
      "lamba" : 23}
      >
      I'd like it to put "/" inbetween the dicts to make it a one
      dimensional dict and look like this:
      {"mays/eggs" : "spam",
      "jam/soda/love" : "dump",
      "lamba" : 23
      >
      }
      In Python you can do anything, even flatten a dictionary:

      from itertools import chain

      def flattendict(d, pfx='', sep='/'):
      if isinstance(d, dict):
      if pfx: pfx += sep
      return chain(*(flatten dict(v, pfx+k, sep) for k, v in
      d.iteritems()))
      else:
      return (pfx, d),

      test = {"mays" : {"eggs" : "spam"},
      "jam" : {"soda" : {"love" : "dump"}},
      "lamba" : 23
      }
      >>print dict(flattendic t(test))
      {'lamba': 23, 'mays/eggs': 'spam', 'jam/soda/love': 'dump'}

      You an even have other separators ;)
      >>print dict(flattendic t(test, sep='.'))
      {'lamba': 23, 'jam.soda.love' : 'dump', 'mays.eggs': 'spam'}

      --
      Arnaud

      Comment

      • Boris Borcic

        #4
        Re: flattening a dict

        George Sakkis wrote:
        On Feb 17, 7:51 am, Arnaud Delobelle <arno...@google mail.comwrote:
        >
        >BTW, I keep using the idiom itertools.chain (*iterable). I guess that
        >during function calls *iterable gets expanded to a tuple. Wouldn't it
        >be nice to have an equivalent one-argument function that takes an
        >iterable of iterables and return the 'flattened' iterable?
        >
        Indeed; I don't have any exact numbers but I roughly use this idiom as
        often or more as the case where chain() takes a known fixed number of
        arguments. The equivalent function you describe is trivial:
        >
        def chain2(iter_of_ iters):
        for iterable in iter_of_iters:
        for i in iterable:
        yield i
        or fwiw

        chainstar = lambda iters : (x for it in iters for x in it)

        - a form that better suggests how to inline it in the calling expression, if
        applicable.

        Cheers, BB

        Comment

        • Arnaud Delobelle

          #5
          Re: flattening a dict

          On Feb 17, 4:03 pm, Boris Borcic <bbor...@gmail. comwrote:
          George Sakkis wrote:
          On Feb 17, 7:51 am, Arnaud Delobelle <arno...@google mail.comwrote:
          >
          BTW, I keep using the idiom itertools.chain (*iterable).  I guess that
          during function calls *iterable gets expanded to a tuple.  Wouldn't it
          be nice to have an equivalent one-argument function that takes an
          iterable of iterables and return the 'flattened' iterable?
          >
          Indeed; I don't have any exact numbers but I roughly use this idiom as
          often or more as the case where chain() takes a known fixed number of
          arguments. The equivalent function you describe is trivial:
          >
          def chain2(iter_of_ iters):
            for iterable in iter_of_iters:
               for i in iterable:
                  yield i
          >
          or fwiw
          >
          chainstar = lambda iters : (x for it in iters for x in it)
          >
          - a form that better suggests how to inline it in the calling expression, if
          applicable.
          Indeed:

          def flattendict(d):
          def gen(d, pfx=()):
          return (x for k, v in d.iteritems()
          for x in (gen(v, pfx+(k,)) if isinstance(v, dict)
          else ((pfx+(k,), v),)))
          return dict(gen(d))

          I don't know, I find the chain(*...) version more readable, although
          this one is probably better. Please, Mr itertools, can we have
          chainstar?

          --
          Arnaud

          Comment

          • Boris Borcic

            #6
            Re: flattening a dict

            Duncan Booth wrote:
            Boris Borcic <bborcic@gmail. comwrote:
            >
            >It is more elementary in the mathematician's sense, and therefore
            >preferable all other things being equal, imo. I've tried to split
            >'gen' but I can't say the result is so much better.
            >>
            >def flattendict(d) :
            > gen = lambda L : (x for M in exp(L) for x in rec(M))
            > exp = lambda L : (L+list(kv) for kv in L.pop().iterite ms())
            > rec = lambda M : gen(M) if isinstance(M[-1],dict) else [M]
            > return dict((tuple(L[:-1]),L[-1]) for L in gen([d]))
            >
            Why, why, why, why are you using lambda here?
            Because the 3 lambdas make manifest that they could be combined into a single
            expression and thus reveal that they replace a single expression.
            It only makes the code harder
            to read
            Matter of perceptions. I myself tend to find

            def g(...) :
            def f(x) :
            return (whatever)
            return y(f)

            a bit hard to follow. So frankly I don't feel it betters anything to write

            def flattendict(d) :
            def gen(L) :
            return (x for M in exp(L) for x in rec(M))

            def exp(L) :
            return (L+list(kv) for kv in L.pop().iterite ms())

            def rec(M) :
            return gen(M) if isinstance(M[-1],dict) else [M]

            return dict((tuple(L[:-1]),L[-1]) for L in gen([d]))

            But whatever to please you

            Cheers, BB


            Comment

            • Arnaud Delobelle

              #7
              Re: flattening a dict

              On Feb 18, 10:22 pm, Steven D'Aprano <st...@REMOVE-THIS-
              cybersource.com .auwrote:
              [...]
              The problem with lambdas comes from people trying to hammer multi-
              expression functions into a single-expression lambda, hence obfuscating
              the algorithm. That's no different from people who obfuscate multi-
              expression functions by writing them as a generator expression.
              I'm sorry if my Python is difficult to understand. That's because
              I've got a bit of a Lisp...

              --
              Arnaud

              Comment

              • Jeff Schwab

                #8
                Re: flattening a dict

                Arnaud Delobelle wrote:
                On Feb 18, 10:22 pm, Steven D'Aprano <st...@REMOVE-THIS-
                cybersource.com .auwrote:
                [...]
                >The problem with lambdas comes from people trying to hammer multi-
                >expression functions into a single-expression lambda, hence obfuscating
                >the algorithm. That's no different from people who obfuscate multi-
                >expression functions by writing them as a generator expression.
                >
                I'm sorry if my Python is difficult to understand. That's because
                I've got a bit of a Lisp...
                That may be the first lambda-related humor I've ever heard.

                Comment

                Working...