grab dict keys/values without iterating ?!

Tim Chase python.list at tim.thechases.com
Tue Dec 10 22:15:10 EST 2013


On 2013-12-11 02:02, Tamer Higazi wrote:
> Is there a way to get dict by search terms without iterating the
> entire dictionary ?!
> 
> Let us assume I have:
> 
> {'Amanda':'Power','Amaly':'Higgens','Joseph':'White','Arlington','Black','Arnold','Schwarzenegger'}
                                                                  ^
Assuming this is a colon...

> I want to grab the dict's key and values started with 'Ar'...
> 
> I could make an iterator and look if it's inside.
> I wasn't able to find it, but I am asking myself if dict has a
> builtin method to get me these key/values on the fly.
> 
> I would thank you for a short reply.

No.

If you want a longer reply, keep reading. :-)

There are a couple ways you could get the results you want, but it
depends on what you want to test.  If you just want to test the
presence/absence of something matching your pattern, you can bail
early with

  if any(k.startswith(s) or v.startswith(s) for k,v in d.iteritems()):
    yep()
  else:
    nope()

which will only pull items from the iterator until the first one is
found.

If you want to find all the results, you have to look at all the
results, either at search time, or at the time of dictionary
construction (although in this case, you'd also need to know the
search term at the time of construction).  That might look something
like

  d = {}
  interesting = []

  def is_interesting(term, *args):
    return any(s.startswith(term) for s in args)

  for key, value, other in data_source:
    if is_interesting(term, key, value):
      interesting.append((key, value))
    d[key] = value

  for key, value in interesting:
    just_iterating_over_those_not_all(key, value)


Alternatively, you could use a different data-structure, something
like (untested)

  SENTINEL = object()
 
  def build_structure(i):
    # "i" is some iterable of key/value pairs
    # such as from {}.iteritems()
    root = {}
    for key, value in i:
      loc = root
      for letter in key:
        loc = loc.setdefault(letter, {})
      loc[SENTINEL] = value
    return root
  
  def just_matches(root, pattern):
    if pattern:
      first_letter = pattern[0]
      if first_letter in root:
        for result in just_matches(root[first_letter], pattern[1:]):
          yield result
    else:
      # show all sub-items
      for k,v in root.iteritems():
        if k is SENTINEL:
          yield v
        else:
          for result in just_matches(v, None):
            yield result
  
  s = build_structure(data.iteritems())
  # print repr(s)
  for result in just_matches(s, "Ar"):
    print result

I'm not sure this is a good trade-off, but it does limit your
iteration to only those that begin with your chosen search term,
rather than all items in the dictionary once the initial
data-structure is built.

(I think in the span of 20 minutes, I managed to recreate a college
homework assignment that took me nearly a week in C)

-tkc










More information about the Python-list mailing list