[dictionary] how to get key by item

Discussion in 'Python' started by Egor Bolonev, Dec 14, 2004.

  1. Egor Bolonev

    Egor Bolonev Guest

    saluton al ciuj

    i know how to get item by key

    ==================
    dict = {10 : 50, 2 : 12, 4 : 43}

    print dict[2]

    >> 12


    but i wonder how to get key by item

    print dict[12]

    >> 2

    ==================


    is there a more fast way than that one (my dictionary is really big)
    ==================
    dict = {10 : 50, 2 : 12, 4 : 43}
    item = 12
    for key in dict.keys():
    if dict[key] == item:
    print key
    break
    ==================
     
    Egor Bolonev, Dec 14, 2004
    #1
    1. Advertising

  2. Egor> i know how to get item by key
    ...
    Egor> but i wonder how to get key by item

    Assuming your dictionary defines a one-to-one mapping, just invert it:

    >>> forward = {10 : 50, 2 : 12, 4 : 43}
    >>> reverse = dict([(v,k) for (k,v) in forward.iteritems()])
    >>> print forward

    {10: 50, 4: 43, 2: 12}
    >>> print reverse

    {50: 10, 43: 4, 12: 2}

    That doubles your storage, so you'll have to trade that off against the
    speed gain of not having to loop over the entire dictionary.

    Skip
     
    Skip Montanaro, Dec 14, 2004
    #2
    1. Advertising

  3. Egor Bolonev

    Roy Smith Guest

    In article <>,
    Skip Montanaro <> wrote:

    > Egor> i know how to get item by key
    > ...
    > Egor> but i wonder how to get key by item
    >
    > Assuming your dictionary defines a one-to-one mapping, just invert it:
    >
    > >>> forward = {10 : 50, 2 : 12, 4 : 43}
    > >>> reverse = dict([(v,k) for (k,v) in forward.iteritems()])
    > >>> print forward

    > {10: 50, 4: 43, 2: 12}
    > >>> print reverse

    > {50: 10, 43: 4, 12: 2}
    >
    > That doubles your storage, so you'll have to trade that off against the
    > speed gain of not having to loop over the entire dictionary.


    Well, you *do* loop over the entire dictionary, but you only do it once,
    when you create the reverse dict. If you are only going to do a single
    lookup, it's no gain, but if you amortize the cost over many lookups,
    it's almost certainly a big win.

    This raises an interesting question. Let's assume that you add all the
    entries to the dictionary before you do any lookups, and you then need
    to lookup things up in both directions. Which is faster, to
    simultaneously build both the forward and reverse dicts, or to just
    build the forward one and when you're done doing that, build the reverse
    one in a single shot with the above list comprehension?

    BTW, does Python really build the intermediate list and throw it away
    after using it to initialize the dictionary, or is it smart enough to
    know that it doesn't really need to build the whole list in memory?
     
    Roy Smith, Dec 14, 2004
    #3

  4. >> That doubles your storage, so you'll have to trade that off against
    >> the speed gain of not having to loop over the entire dictionary.


    Roy> Well, you *do* loop over the entire dictionary, but you only do it
    Roy> once, when you create the reverse dict. If you are only going to
    Roy> do a single lookup, it's no gain, but if you amortize the cost over
    Roy> many lookups, it's almost certainly a big win.

    Sure, but the OP said his dictionary was big. It's up to him to decide
    whether the space-time tradeoff is worth it (or even possible).

    Roy> BTW, does Python really build the intermediate list and throw it
    Roy> away after using it to initialize the dictionary, or is it smart
    Roy> enough to know that it doesn't really need to build the whole list
    Roy> in memory?

    That's why I called .iteritems() in my example. It won't generate the
    entire list of tuples as .items() would.

    Skip
     
    Skip Montanaro, Dec 14, 2004
    #4
  5. Egor Bolonev

    Roy Smith Guest

    Skip Montanaro <> wrote:

    > Roy> BTW, does Python really build the intermediate list and throw it
    > Roy> away after using it to initialize the dictionary, or is it smart
    > Roy> enough to know that it doesn't really need to build the whole list
    > Roy> in memory?
    >
    > That's why I called .iteritems() in my example. It won't generate the
    > entire list of tuples as .items() would.


    I know it won't generate the list of items from the forward dict, but I
    was thinking of the list generated by the list comprehension, passed as
    the argument to the reverse dict constructor. That's the throw-away
    list I was thinking of (see Tim Delaney's response to my post).
     
    Roy Smith, Dec 14, 2004
    #5
  6. Egor Bolonev

    Aahz Guest

    In article <>,
    Skip Montanaro <> wrote:
    >
    >Assuming your dictionary defines a one-to-one mapping, just invert it:
    >
    > >>> forward = {10 : 50, 2 : 12, 4 : 43}
    > >>> reverse = dict([(v,k) for (k,v) in forward.iteritems()])
    > >>> print forward

    > {10: 50, 4: 43, 2: 12}
    > >>> print reverse

    > {50: 10, 43: 4, 12: 2}
    >
    >That doubles your storage, so you'll have to trade that off against the
    >speed gain of not having to loop over the entire dictionary.


    To be precise, it doubles the storage of the *dictionary*, but it does
    *NOT* double the storage of the keys and items. Depending on how big
    those are, the cost of building a second dict might be mostly lost in the
    noise.
    --
    Aahz () <*> http://www.pythoncraft.com/

    "19. A language that doesn't affect the way you think about programming,
    is not worth knowing." --Alan Perlis
     
    Aahz, Dec 14, 2004
    #6
  7. Egor Bolonev

    Keith Dart Guest

    Skip Montanaro wrote:
    > Egor> i know how to get item by key
    > ...
    > Egor> but i wonder how to get key by item
    >
    > Assuming your dictionary defines a one-to-one mapping, just invert it:
    >
    > >>> forward = {10 : 50, 2 : 12, 4 : 43}
    > >>> reverse = dict([(v,k) for (k,v) in forward.iteritems()])
    > >>> print forward

    > {10: 50, 4: 43, 2: 12}
    > >>> print reverse

    > {50: 10, 43: 4, 12: 2}
    >
    > That doubles your storage, so you'll have to trade that off against the
    > speed gain of not having to loop over the entire dictionary.
    >
    > Skip


    But beware that all the items in the original dictionary must be
    hashable. The example shows just integers, so I assume they are in this
    case. But generally, this may not work.



    --
    \/ \/
    (O O)
    -- --------------------oOOo~(_)~oOOo----------------------------------------
    Keith Dart <>
    vcard: <http://www.kdart.com/~kdart/kdart.vcf>
    public key: ID: F3D288E4 URL: <http://www.kdart.com/~kdart/public.key>
    ============================================================================
     
    Keith Dart, Dec 14, 2004
    #7
  8. Skip Montanaro wrote:

    > That doubles your storage


    careful: it creates another dictionary structure with the same size as the first
    one, but it doesn't copy the objects in the dictionary.

    so whether it doubles the actual memory usage depends on what data you
    have in the dictionary (last time I checked, ints and dictionary slots were the
    same size, but I cannot think of any other object that isn't larger...)

    (but you knew that, of course)

    </F>
     
    Fredrik Lundh, Dec 14, 2004
    #8
  9. Egor Bolonev

    Ola Natvig Guest

    Skip Montanaro wrote:
    > Egor> i know how to get item by key
    > ...
    > Egor> but i wonder how to get key by item
    >
    > Assuming your dictionary defines a one-to-one mapping, just invert it:
    >
    > >>> forward = {10 : 50, 2 : 12, 4 : 43}
    > >>> reverse = dict([(v,k) for (k,v) in forward.iteritems()])
    > >>> print forward

    > {10: 50, 4: 43, 2: 12}
    > >>> print reverse

    > {50: 10, 43: 4, 12: 2}
    >
    > That doubles your storage, so you'll have to trade that off against the
    > speed gain of not having to loop over the entire dictionary.
    >
    > Skip


    If some keys has the same value as the item this will cause problems
    because keys in your result dictionary can be overwritten. Could it be a
    option to build the result dictionary as a dictionary with the values
    as the keys, and lists of keys as the value. Perhaps you need to use a
    loop for this.

    --
    --------------------------------------
    Ola Natvig <>
    infoSense AS / development
     
    Ola Natvig, Dec 14, 2004
    #9
  10. Egor Bolonev

    Nick Coghlan Guest

    Ola Natvig wrote:
    > If some keys has the same value as the item this will cause problems
    > because keys in your result dictionary can be overwritten. Could it be a
    > option to build the result dictionary as a dictionary with the values
    > as the keys, and lists of keys as the value. Perhaps you need to use a
    > loop for this.
    >


    <<Python 2.4>>

    ..>>> d = dict(foo=1, bar=1, bob=7, jane=42, mary=16, fred=16)
    ..>>> from itertools import groupby
    ..>>> val = d.__getitem__
    ..>>> grouped = groupby(sorted(d.iterkeys(), key=val), val)
    ..>>> r = dict((value, list(keys)) for value, keys in grouped)
    ..>>> r
    {16: ['mary', 'fred'], 1: ['bar', 'foo'], 42: ['jane'], 7: ['bob']}

    Cheers,
    Nick.

    --
    Nick Coghlan | | Brisbane, Australia
    ---------------------------------------------------------------
    http://boredomandlaziness.skystorm.net
     
    Nick Coghlan, Dec 14, 2004
    #10
  11. Fredrik> Skip Montanaro wrote:
    >> That doubles your storage


    Fredrik> careful: it creates another dictionary structure with the same
    Fredrik> size as the first one, but it doesn't copy the objects in the
    Fredrik> dictionary.

    Yes, sorry. The OP indicated the original dictionary was very big, so it
    seemed like duplicating the dictionary storage would potentially be costly
    since dictionaries hold extra storage (on average, twice the storage needed
    to hold the references to its keys?) to support O(1) average time lookup.

    Skip
     
    Skip Montanaro, Dec 14, 2004
    #11
  12. Ola> If some keys has the same value as the item this will cause
    Ola> problems because keys in your result dictionary can be
    Ola> overwritten.

    That's why I said, "assuming your dictionary defines a one-to-one
    mapping...".

    Skip
     
    Skip Montanaro, Dec 14, 2004
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Guest
    Replies:
    2
    Views:
    5,651
    wwwtar
    Nov 2, 2006
  2. abcd
    Replies:
    3
    Views:
    247
    Bruno Desthuilliers
    Apr 3, 2007
  3. avital

    Item has already been added. Key in dictionary

    avital, Dec 12, 2006, in forum: ASP .Net Web Controls
    Replies:
    1
    Views:
    539
    Steve C. Orr [MCSD, MVP, CSM, ASP Insider]
    Dec 19, 2006
  4. Samuel
    Replies:
    8
    Views:
    133
    [MSFT]
    Oct 14, 2004
  5. idoh
    Replies:
    0
    Views:
    211
Loading...

Share This Page