3
\$\begingroup\$

dem_rows and dem_cols contain float values for a number of things i can identify in an image, but I need to get the nearest pixel for each of them, and than to make sure I only get the unique points, and no duplicates.

The problem is that this code is ugly and as far as I get it, as unpythonic as it gets. If there would be a pure-numpy-solution (without for-loops) that would be even better.

# next part is to make sure that we get the rounding done correctly, and than to get the integer part out of it 
# without the annoying floatingpoint-error, and without duplicates
fielddic={}
for i in range(len(dem_rows)):
    # here comes the ugly part: abusing the fact that i overwrite dictionary keys if I get duplicates
    fielddic[int(round(dem_rows[i]) + 0.1), int(round(dem_cols[i]) + 0.1)] = None
# also very ugly: to make two arrays of integers out of the first and second part of the keys 
field_rows = numpy.zeros((len(fielddic.keys())), int)
field_cols = numpy.zeros((len(fielddic.keys())), int)
for i, (r, c) in enumerate(fielddic.keys()):
    field_rows[i] = r
    field_cols[i] = c
\$\endgroup\$

migrated from stackoverflow.com Oct 31 '13 at 3:15

This question came from our site for professional and enthusiast programmers.

3
\$\begingroup\$

I'm not sure what you are doing, exactly, but looping over range(len(...)) is never very pythonic. Since you only use the index to look up values, you should just take the pairs using zip.

Also, that round() + 0.1 thing is unnecessary. Floats represent all integers in their accurate area exactly. If you are outside the accurate area (i.e. an exponent larger than the number of mantissa bits), that addition will not change the value of the float either. Thus, you can simply cast the result of round() to an integer.

If you need to take the unique items of something, the best way is to not use a dict, but a set.

int_rows = map(lambda x: int(round(x)), dem_rows)
int_cols = map(lambda x: int(round(x)), dem_cols)
s = set(zip(int_rows, int_cols))

Then iterate over the set, or unzip it into two sequences for constructing the arrays.

Note: In python 2.x map and zip create lists, so you may want to use itertools.izip and imap. In python 3.x they are fine as is.

\$\endgroup\$
  • \$\begingroup\$ but i cant cast round() to an array, so i am still stuck with an ugly loop there- since dem_rows are floats and if i take the set of the zip, i just end up with the same thing, and i want to get rid of the for-loops) \$\endgroup\$ – usethedeathstar Oct 25 '13 at 9:35
  • \$\begingroup\$ You can map the elements to ints, I'll update the answer. \$\endgroup\$ – otus Oct 25 '13 at 9:38
  • \$\begingroup\$ and than how would it be best to iterate over the set or unzip and reconstruct? \$\endgroup\$ – usethedeathstar Oct 25 '13 at 9:48
  • \$\begingroup\$ You can turn it back into two sequences using u_rows, u_cols = zip(*s). I'm not sure if you can pass those directly to numpy's array constructors or if you need to use tuple() first in python 3.x where zip returns iterators. \$\endgroup\$ – otus Oct 25 '13 at 9:54
  • \$\begingroup\$ i am using 2.7 still \$\endgroup\$ – usethedeathstar Oct 25 '13 at 9:55
1
\$\begingroup\$

This is very unpythonic, however very common for Python newbies

 for i in range(len(something)):
     do_someting_with(i)  

You can iterate over items in the following way:

for item in something:
    do_something_with(item)

or if you need also the index:

for idx, item in enumerate(something):
    do_something_with(item)
    do_something_with_idx(idx)

If you expect a list to comeout you can use list comperhansiom:

result = [ do_someting_with(item) for item in something ]

Or you can use some functional programming style:

result = map( do_someting_with, something ) 
\$\endgroup\$
0
\$\begingroup\$

Ok, i think i have found the best solution myself, with a little help from Otus, for the zip-set-unzip part, though i think my way of getting it to integers is more pythonic?

r1 = numpy.array(numpy.round(dem_rows), int)
c1 = numpy.array(numpy.round(dem_cols), int)
field_rows, field_cols = zip(*set(zip(r1, c1)))
\$\endgroup\$
  • \$\begingroup\$ This solution was copied from Rev 1 of the question. If @usethedeathstar would repost this as a self-answer, then we can remove this post. \$\endgroup\$ – 200_success Nov 13 '15 at 8:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.