0

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'}}
  • Do you have to do something with the node if it does exist, or do you just have to know it exists? – Loocid Oct 31 '18 at 01:25
  • A really naive way to do this is `'AccountRoot' in str(my_dict)` – slider Oct 31 '18 at 01:29
  • I just have to filter the whole transaction out. @slider if I did it that way would could there be issues? – WizardCovfefe Oct 31 '18 at 01:34
  • @slider: *A really naive way to do this is 'AccountRoot' in str(my_dict)* -- that will not differentiate between a key and a value. – dawg Oct 31 '18 at 01:41
  • @WizardCovfefe we're converting the dictionary to a string representation and doing a string search. So it's both inefficient and can be inaccurate (for example if the string we're searching for is a substring of a larger string). – slider Oct 31 '18 at 01:41
  • @dawg yes, I believe that is what the OP wants (in the example, `AccountRoot` is actually a value). – slider Oct 31 '18 at 01:41
  • But it would also return True for a key with that value. Loosing the ability to know if it is a key or value is kinda weak. – dawg Oct 31 '18 at 02:21

2 Answers2

2

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
Saedeas
  • 1,548
  • 8
  • 17
0

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
UtahJarhead
  • 2,091
  • 1
  • 14
  • 21