views:

119

answers:

2

hello!

i have a list of dictionaries. there are several points inside the list, some are multiple. When there is a multiple entry i want to calculate the average of the x and the y of this point. My problem is, that i don't know how to loop through the list of dictionaries to compare the ids of the points!

when i use something like that:

for i in list:
  for j in list:
    if i['id'] == j['id']:
      point = getPoint(i['geom'])
      ....

sorry, the formating is a little bit tricky... the second loop is inside the first one... i think it compares the first entry of the list, so it's the same... so i have to start in the second loop with the second entry, but i can't do that with i-1 because i is the hole dictionary... Someone an idea? thanks in advance!

 for j in range(1, len(NEWPoint)):
      if i['gid']==j['gid']:
         allsamePoints.append(j)
      for k in allsamePoints:
         for l in range(1, len(allsamePoints)):
            if k['gid']==l['gid']:
                Point1 = k['geom']
                Point2=l['geom']
                X=(Point1.x()+Point2.x())/2
                Y=(Point1.y()+Point2.y())/2
                AVPoint = QgsPoint(X, Y)
                NEWReturnList.append({'gid': j['gid'], 'geom': AVPoint})
                del l
      for m in NEWReturnList:
          for n in range(1, len(NEWReturnList)):
              if m['gid']==n['gid']:
                 Point1 = m['geom']
                 Point2=n['geom']
                 X=(Point1.x()+Point2.x())/2
                 Y=(Point1.y()+Point2.y())/2
                 AVPoint = QgsPoint(X, Y)
                 NEWReturnList.append({'gid': j['gid'], 'geom': AVPoint})
                 del n
              else:
                 pass

ok, i think... at the moment thats more confusing :)...

+3  A: 

One way would be changing the way you store your points, because as you already noticed, it's hard to get what you want out of it.

A much more useful structure would be a dict where the id maps to a list of points:

from collections import defaultdict
points_dict = defaultdict(list)

# make the new dict
for point in point_list:
    id = point["id"]
    points_dict[id].append(point['geom'])

def avg( lst ):
    """ average of a `lst` """
    return 1.0 * sum(lst)/len(lst)

# now its simple to get the average
for id in points_dict:
    print id, avg( points_dict[id] )
THC4k
I retracted the comment I was in the middle of writing as THC4k is correct. A list of dicts is not ideal at all -- more naturally, you have ONE dict in which you can deduplicate the points first. +1However, THC4k, it would be nice if you added code on how to build such a dict from the list, to make it clearer for the OP.
chryss
so, when i go with the points_dict[id].append(...) i get a dictionary with several items with different ids and geometries?!i wanted to do that with the list of dictionaries, because i couldn't find anything for storing several items (like in a excel table) in a dictionary...
notice `defaultdict(list)` uses the builtin `list` which is why you should **never** use `list` for a variable name
gnibbler
A dictionary is a mapping from any (hashable) type to any type of data. The canonical dictionary maps strings to strings (`dict["spam"] = "ham"`) but this is not the only thing you can do. In this case, THC4k is mapping a string (the `id` of a point) to a list of points with those `id`s. The `collections.defaultdict` means that a string we haven't processed yet maps to `[]`.
katrielalex
ok, so i will have one entry for the id and to that several point-geometries... mh, i think i have to find another solution, because the calculation of the points itself takes already a lot of time... and they are stored to the list of dictionaries... so i will have to change the calculation, because otherwise i am storing these points during the calculation to the list of dictionary and then convert it to a dictionary.... thats not very clever...so you think it will be too much trouble to make that loop with the second entry?!?!
@pythonacc: It doesn't compute anything new, it just takes the points from your first list and puts them into a different dictionary. Of course you can skip generating the first list if you don't need it elsewhere ...
THC4k
A: 

I'm not totally sure what you want to do, but I think list filtering would help you. There's built-in function filter, which iterates over a sequence and for each item it calls user-defined function to determine whether to include that item in the resulting list or not.

For instance:

def is4(number):
   return number == 4

l = [1, 2, 3, 4, 5, 6, 4, 7, 8, 4, 4]
filter(is4, l) # returns [4, 4, 4, 4]

So, having a list of dictionaries, to filter out all dictionaries with certain entry equal to a given value, you could do something like this:

def filter_dicts(dicts, entry, value):
   def filter_function(d):
      if entry not in d:
         return False
      return d[entry] == value
   return filter(filter_function, dicts)

With this function, to get all dictionaries with the "id" entry equal to 2, you can do:

result = filter_dicts(your_list, "id", 2)

With this, your main loop could look something like this:

processed_ids = set()
for item in list:
   id = item['id']
   if id in processed_ids:
      continue
   processed_ids.add(id)
   same_ids = filter_dicts(list, "id", id)
   # now do something with same_ids

I hope I understood you correctly and that this is helpful to you.

Honza
oh great!!! thanks a lot... that looks good... i have to read it again and try it with mine!
it's working!jipie!