[Tutor] updating a list under conditions -- I think my way might "smell"

Chad Crabtree flaxeater at yahoo.com
Mon Oct 4 16:51:51 CEST 2004


Brian van den Broek wrote:

> Hi All,
>
> I have a situation where I have a list of dictionary keys, 
> representing the order of occurrence of the dictionary values in
some 
> datafile. (In my actual case, the values are themselves
dictionaries, 
> storing metadata on the data items in the file.)
>
> I want to add a new value to the dictionary, putting its key in the

> list such that it occurs after the first key that meets condition A

> and before the first (among those strictly after the A-meeter) that

> meets condition B.
>
> Given my data, I know condition A will be met by an early item in
the 
> list of dictionary keys. Condition B might not be meet amongst the 
> post A-meeter items. (It is certain to be met before, but if it is,

> meeting condition B is not relevant.) If it is not, I want to add
my 
> new item at the end of the list that stores the orders.
>
> I have a way that works, but I'm not too sure about it's "smell".
The 
> sample code below abstracts my working method into a manageable toy

> example. (My actual use has fairly complicated conditions, and I
found 
> it easier to write ones which just displayed the logic I am worried

> about than to extract the relevant functions in a way that would
leave 
> them short enough to post, yet still in a runnable state.) So, I'm
not 
> advancing the broad design here as good. It's just a quick way to 
> illustrate the use  of location = '' and the try/except block that 
> form the heart of my present solution.
>
> def find_first_not_multiple_of_10(target):
>     for i in target:
>         if 0 != my_dict[i] % 10:
>             # "Condition A" in the description above.
>             # Given my data, I am certain such an i exists early in
>             # the list I am working with. It could even be first.
>             return i
>
> def get_insert_location(target, start):
>     location = ''
>     # location given a value that evaluates to 'False' and that
>     # cannot serve as a list index. (Elsewhere in my code I need
>     # to be able to do an if test on location, so I need the
False.)
>     for i in target[start:]:
>         if my_dict[i] > 90:
>             # "Condition B" in the description above.
>             # there may not be such an i. If there is, use its
index.
>             location = target.index(i)
>             break
>     return location
>
> def update(target, item):
>     start_search = find_first_not_multiple_of_10(target) + 1
>     # + 1 to get past the first A-meeter
>     location = get_insert_location(target, start_search)
>     try:
>         target[location:location] = [item]
>     except TypeError:
>         # error raised if there is no i in target[start:] such that
>         # my_dict[i] > 90. If raised, put new item at end.
>         target.append(item)
>     print target
>
> my_dict = {1:110, 2:35, 3:50, 4:80, 5:95, 6:70}
> my_list = [1, 3, 2, 6, 5, 4]
> my_list2 = [1, 3, 2, 6, 4]  # The item meeting "Condition B"
removed
>
> my_dict[7] = 45
> update(my_list, 7)
> update(my_list2, 7)
>
> >>>
> [1, 3, 2, 6, 7, 5, 4]
> [1, 3, 2, 6, 4, 7]
>
> So, this way works as desired. But is there a better way to do
this?
>
> I get that that is hard to answer seeing neither the data I am
working 
> on, nor the reason I need the if test on location, etc. But my
script 
> is pushing to 1,000 lines and the data is many MB, so that just
isn't 
> practical to post ;-)
>
> Best and thanks to all,
>
> Brian vdB
>
I recently had need for a similar construct, basically I needed a 
dictionary that remembered the order in which I add them.  I looked
on 
google and found one that almost worked I updated it and it seems to 
behave well, it has both list like methods and dictionary methods, 
append, insert, sort and others I'm attaching the file it may be
helpful 
to you.




		
_______________________________
Do you Yahoo!?
Declare Yourself - Register online to vote today!
http://vote.yahoo.com
-------------- next part --------------
from random import choice

def uid():
    hexuid=['1', '2', '3', '4', '5', '6', '7', 
    '8', '9', 'a', 'b', 'c', 'd', 'e', 'f']
    return ''.join([choice(hexuid) for x in range(20)])


################################################################################
#  Sequential Dictionary Class                                                 #
#                                                                              #
#  by Wolfgang Grafen                                                          #
#                                                                              #
#  Version 0.0    29. June 1999                                                #
#                                                                              #
#  email to: WolfgangGrafen at gmx.de                                             #
#                                                                              #
#    updated by Chad Crabtree                                                  #
#                                                                              #
#    Version 0.1 Sept 11 2004                                                  #
#                                                                              #
#    email to: flaxeater at yahoo.com                                             #
#                                                                              #
################################################################################

class seqdict(dict):
  def __init__(self,List=[],Dict={}):
    if type(List)==type({}):
      self.list = List.keys()
      self.dict = List.copy()
    elif List and not Dict:
      self.list=[]
      self.dict={}
      for i,j in List:
        self.list.append(i)
        self.dict[i]=j
    elif type(List)==type(Dict)==type([]):
      self.list = List
      self.dict = {}
      for key,value in map(None,List,Dict):
        self.dict[key] = value
    else:
      self.list,self.dict = List[:],Dict.copy()
      
  def append(self,key,value=''):
    "list like function that adds a key value pair to seqdict"
    if type(key)==type({}):
        for k,v in k.items():
            if self.dict.has_key(k):
                self.list.remove(k)
            self.list.append(k)
            self.dict[k]=v
        
    if self.dict.has_key(key):
      self.list.remove(key)
    self.list.append(key)
    self.dict[key]=value
  def check(self):
    "checks to make sure that it is one to one"
    if len(self.dict)==len(self.list):
      l1=self.list[:];l1.sort()
      l2=self.dict.keys();l2.sort()
      return bool(l1==l2)
    return False
  def clear(self):
    "resets the seqdict to []"
    self.list=[];self.dict={}
  def copy(self):
    "returns deep copy of self"
    if self.__class__ is seqdict:
      return self.__class__(self.list,self.dict)
    return self[:]
  def __cmp__(self,other):
    "compars to seqdicts"
    return cmp(self.dict,other.dict) or cmp(self.list,other.list)
  def __getitem__(self,key):
    if type(key)==type([]):
      newdict={}
      for i in key:
        newdict[i]=self.dict[i]
      return self.__class__(key,newdict)
    return self.dict[key]
  def __setitem__(self,key,value):
    if not self.dict.has_key(key):
      self.list.append(key)
    self.dict[key]=value
  def __delitem__(self, key):
    del self.dict[key]
    self.list.remove(key)      
  def __getslice__(self,start,stop):
    start = max(start,0); stop = max(stop,0)
    newdict = self.__class__()
    for key in self.list[start:stop]:
      newdict.dict[key]=self.dict[key]
    newdict.list[:]=self.list[start:stop]
    return newdict
  def __setslice__(self,start,stop,newdict):
    start = max(start,0); stop = max(stop,0)
    delindexes = []
    for key in newdict.keys():# if the dict has
        #the keys then it delets them
      if self.dict.has_key(key):
        index = self.list.index(key)
        delindexes.append(index)
        if index < start:
          start = start - 1
          stop  = stop  - 1
        elif index >= stop:
          pass
        else:
          stop  = stop - 1
    delindexes.sort()
    delindexes.reverse()
    for index in delindexes:
      key = self.list[index]
      del   self.dict[key]
      del  self.list[index]
    for key in self.list[start:stop]:
      del self.dict[key]
    self.list[start:stop] = newdict.list[:]
    self.update(newdict.dict)
  def __delslice__(self, start, stop):
      start = max(start, 0); stop = max(stop, 0)
      for key in self.list[start:stop]:
        del self.dict[key]
      del self.list[start:stop]
  def __add__(self,other):
    "add's two seqdicts together"
    newdict = self.__class__()
    for key,value in self.items()+other.items():
      newdict.append(key,value)
    return newdict    
  def __radd__(self,other):
    "add's two seqdicts togheter"
    newdict = self.__class__()
    for key,value in other.items()+self.items():
      newdict.append(key,value)
    return newdict   
  def count(self,value):
    "count of values in dict should only ever be one"
    vallist = self.dict.values()
    return vallist.count(value)
  def extend(self,other):
    "similar to append may remove"
    self.update(other)
  def filter(self,function):
    "remove key,values by function non-destructive"
    liste=filter(function,self.list)
    dict = {}
    for i in liste:
      dict[i]=self.dict[i]
    return self.__class__(liste,dict)
  def get(self, key, failobj=None):
        "dictionary method return value of key"
        return self.dict.get(key, failobj)
  def index(self,key):
      "list like method that returns the index of a key"
      return self.list.index(key)
  def insert(self,i,x):
      "Insert by index, just like a list"
      y=seqdict(x)
      self.__setslice__(i,i,y)
      lst=[]
      temp={}
      for n,v in enumerate(self.list):
          if temp.has_key(v):
              temp[v]=(n,True)
          else:
              temp[v]=(0,False)
      for k,v in temp.items():
          if v[1]: #if value (there's more than one instance in self.list)
              lst.append(v[0]) #append the index
      lst.sort()
      lst.reverse()
      for x in lst: #now remove duplicates
        del self.list[x]
        
  def items(self):
      "return tuple of key,value pairs for iteration"
      return map(None,self.list,self.values())
  def has_key(self,key):
      "truth test for key existence"
      return self.dict.has_key(key)
  def keys(self):
      "return the keys of the seqdict"
      return self.list
  def map(self,function):
    "map function for the values"
    return self.__class__(map(function,self.items()))
  def values(self):
    "return a list of values in the order they where entered"
    nlist = []
    for key in self.list:
      nlist.append(self.dict[key])
    return nlist
  def __len__(self):
      "returns the length of the internal list"
      return len(self.list)
  def pop(self,key=None):
    "pop an item off the top removed"
    if key==None:
      pos = -1
      key = self.list[pos]
    else:
      pos = self.list.index(key)
    tmp = self.dict[key]
    del self.dict[key]
    return {self.list.pop(pos):tmp}
  def push(self,key,value):
    "same as append"
    self.append(key,value)
  def reduce(self,function,start=None):
    "returns a single value based on funtion see reduce"
    return reduce(function,self.items(),start)
  def remove(self,key):
    "remove by key not index"
    del self.dict[key]
    self.list.remove(key)
  def reverse(self):self.list.reverse()
  def sort(self,*args):
      "sorts the keys optional algorythm to sort with"
      apply(self.list.sort,args)
  def split(self,function,Ignore=None):
    splitdict = seqdict() #self.__class__()
    for key in self.list:
      skey = function(key)
      if skey != Ignore:
        if not splitdict.has_key(skey):
          splitdict[skey] = self.__class__()
        splitdict[skey][key] = self.dict[key]
    return splitdict
  def swap(self):
    "turns all the values into keys and keys into values"
    tmp = self.__class__(map(lambda (x,y):(y,x),self.items()))
    self.list,self.dict = tmp.list,tmp.dict
  def update(self,newdict):
    for key,value in newdict.items():
      self.__setitem__(key,value)
  def slice(self,From,To=None,Step=1):
    From       = self.list.index(From)
    if To:To   = self.list.index(To)
    else :
      To = From + 1
    List = range(From,To,Step)
    def getitem(pos,self=self):return self.list[pos]
    return self.__getitem__(map(getitem,List))
  def __repr__(self):return 'seqdict(\n%s,\n%s)'%(self.list,self.dict)

def test():
    #see if it really is a unique ID
    def testUID():
        res={}
        for x in range(10000):
            z=uid()
            if res.has_key(z):
                res[z]+=1
            else:
                res[z]=1
        holder=False
        for k,v in res.iteritems():
            if v>1:
                print "Failure Key:%s Value:%s" %(str(k),str(v))
                holder=True
        if holder==False:
            print "No Duplicate UID's"
    testUID()
    def testseqdict():
        globals()['d']=seqdict()
        d['dog']='cat'
        d['cat']='dog'
        d.insert(1,{'go':'fast',"fast":"go"})
        print d.check()
        d.index('dog')
        print d
    testseqdict()
if __name__=='__main__':
    test()
--------------060709090809010706030901--


More information about the Tutor mailing list