WizardCovfefe
WizardCovfefe

Reputation: 27

Is there an easy way to see if a value exists in a complicated dictionary?

Below is an example of a complicated dictionary that I am looping through. I want to check if "AccountRoot" appears in the dictionary. Be aware that I am looping through many of these dictionaries and the format changes. Thus I was wondering if there was a function like .find(). I could not find any and it seems like .find() does not work.

Example Dict;

{'hash': '752F3B5CEE85F3C2DC60041DCAC4777BECE9CC11585225383F8178EBC2ACFB16',
 'ledger_index': 108843,
 'date': '2013-01-18T22:27:20+00:00',
 'tx': {'TransactionType': 'OfferCreate',
  'Flags': 0,
  'Sequence': 3,
  'TakerPays': '499950000',
  'TakerGets': {'value': '0.05',
   'currency': 'BTC',
   'issuer': 'r4aZ4aqXHfrcYfuFrTqDmSopfgPHnRS9MZ'},
  'Fee': '10',
  'SigningPubKey': '027008A4A7AED7B5426EAC46691CFCAC8CA3CF2773D1CAC4074F0BC58EC24BE883',
  'TxnSignature': '3046022100C38236B533936B4A328346D5246570976B8A1390655EC1B6F4090C42AE73FD8D022100D49E5498C40D90AF7BD02F2818EE04F1D0F6B0C76F0325997190D56BF4B9D82D',
  'Account': 'r4aZ4aqXHfrcYfuFrTqDmSopfgPHnRS9MZ'},
 'meta': {'TransactionIndex': 0,
  'AffectedNodes': [{'CreatedNode': {'LedgerEntryType': 'DirectoryNode',
     'LedgerIndex': '0A624575D3C02D544B92F23F6A8BDF3B10745427B731613820A1695AFF11993B',
     'NewFields': {'ExchangeRate': '5E2386099B1BF000',
      'RootIndex': '0A624575D3C02D544B92F23F6A8BDF3B10745427B731613820A1695AFF11993B',
      'TakerGetsCurrency': '0000000000000000000000004254430000000000',
      'TakerGetsIssuer': 'E767BCB9E1A31C46C16F42DA9DDE55792767F565'}}},
   {'CreatedNode': {'LedgerEntryType': 'DirectoryNode',
     'LedgerIndex': '165845E192D2217A6518C313F3F4B2FD676EE1619FF50CB85E2386099B1BF000',
     'NewFields': {'ExchangeRate': '5E2386099B1BF000',
      'RootIndex': '165845E192D2217A6518C313F3F4B2FD676EE1619FF50CB85E2386099B1BF000',
      'TakerGetsCurrency': '0000000000000000000000004254430000000000',
      'TakerGetsIssuer': 'E767BCB9E1A31C46C16F42DA9DDE55792767F565'}}},
   {'ModifiedNode': {'LedgerEntryType': 'AccountRoot',
     'PreviousTxnLgrSeq': 108839,
     'PreviousTxnID': '8B2921C5222A6814BCF7602A18FEACE94797A644AF893A43FB642C172CC14ED0',
     'LedgerIndex': '481DA662E465CC7888FD3750A0952F2003D78DCAA8CB2E91088E862BB7D30B98',
     'PreviousFields': {'Sequence': 3,
      'OwnerCount': 0,
      'Balance': '9999999980'},
     'FinalFields': {'Flags': 0,
      'Sequence': 4,
      'OwnerCount': 1,
      'Balance': '9999999970',
      'Account': 'r4aZ4aqXHfrcYfuFrTqDmSopfgPHnRS9MZ'}}},
   {'CreatedNode': {'LedgerEntryType': 'Offer',
     'LedgerIndex': '9AABB5DCD201AE7FB0F9B7F90083F48B7451977B2419339ADFEBD8876B54EB66',
     'NewFields': {'Sequence': 3,
      'BookDirectory': '165845E192D2217A6518C313F3F4B2FD676EE1619FF50CB85E2386099B1BF000',
      'TakerPays': '499950000',
      'TakerGets': {'value': '0.05',
       'currency': 'BTC',
       'issuer': 'r4aZ4aqXHfrcYfuFrTqDmSopfgPHnRS9MZ'},
      'Account': 'r4aZ4aqXHfrcYfuFrTqDmSopfgPHnRS9MZ'}}}],
  'TransactionResult': 'tesSUCCESS'}}

Upvotes: 0

Views: 66

Answers (2)

Saedeas
Saedeas

Reputation: 1578

Answer here: Finding a key recursively in a dictionary

Posting this so people can encounter the answer if they search using different terms.

I would use alecxe's answer using the stack of iterators pattern defined here by Gareth Rees: http://garethrees.org/2016/09/28/pattern/

Code in case other links are destroyed:

def search(d, key, default=None):
    """
    Return a value corresponding to the specified key in the (possibly
    nested) dictionary d. If there is no item with that key, return
    default.
    """
    stack = [iter(d.items())]
    while stack:
        for k, v in stack[-1]:
            if isinstance(v, dict):
                stack.append(iter(v.items()))
                break
            elif k == key:
                return v
        else:
            stack.pop()
    return default

This code allows you to avoid the problem of exceeding the maximum recursion depth present in some other solutions.

Edit: realized you're simply trying to find out if a value exists in the dictionary.

You can simply modify the for loop to something like this, and it should work for a simple true/false search.

def search(d, key, default=False):
    """
    Return a value corresponding to the specified key in the (possibly
    nested) dictionary d. If there is no item with that key, return
    default.
    """
    stack = [iter(d.items())]
    while stack:
        for k, v in stack[-1]:
            if isinstance(v, dict):
                stack.append(iter(v.items()))
                break
            elif k == key:
                return True
            elif v == key:
                return True
        else:
            stack.pop()
    return default

Upvotes: 2

UtahJarhead
UtahJarhead

Reputation: 2217

There's potentially an easier way, but here's how I've done something similar. I've modified it for your use case.

import copy

def traverse_dict(_obj):
    _obj_2 = copy.deepcopy(_obj)
    if isinstance(_obj_2, dict):
        for key, value in _obj_2.items():
            if key == 'your_value':
                do_your_stuff()
            _obj_2[key] = traverse_dict(value)
    elif isinstance(_obj, list):
        for offset in range(len(_obj_2)):
            _obj_2[offset] = traverse_dict(_obj_2[offset])
    return _obj_2

Upvotes: 0

Related Questions