3

I am trying to iterate over a list of lists of lists... of list of pair of coordinates in python and I want to sum a value to each of these pair of coordinates but I also want to keep the structure.

I think an example is worth more than a thousand words so:

coordinates = [[[-15.418887, 28.180395], [-15.418887, 28.180395]],
 [[-15.794088, 28.018681], [-15.794088, 28.018681]]]

This is a very basic example but is not the real case. In the real each of the list has variables lengths except for the pair of coordinates. So maybe there are 4 lists until the list of list of pair coordinates or it could be 3, it is variable

I want to add 3 (for example) to each of these coordinates but keeping the original structure ( I don't want to flat the list of lists of list ....)

Maybe this is useful for trying to answer the question:

  • I have a geojson file and I want to move a feature ( a region) to another place. To do this I am trying to sum a constant value to latitude and longitude to each coordinate of the region
  • I think this could be done using recursion but I am not sure how

Any help is appreciated.

Angel
  • 1,959
  • 18
  • 37
  • Is it guaranteed to have two nested lists in one list? – Harsh Dec 22 '20 at 19:05
  • @Harsh no, it could be variable, could be three, four or more nested lists. It is variable – Angel Dec 22 '20 at 19:06
  • Does this answer your question? [Flatten an irregular list of lists](https://stackoverflow.com/questions/2158395/flatten-an-irregular-list-of-lists) – Renat Dec 22 '20 at 19:06
  • You can convert the list to a numpy list and then simply do the operation you want on the list like `cd = np.array(coordinates)` and `cd = cd + 3` – Harsh Dec 22 '20 at 19:08
  • @Renat as I said, I want to keep the original structure I don't want to flatten the list of lists.... So it is not useful, thanks anyway. – Angel Dec 22 '20 at 19:11
  • So you basically have an n-ary tree that you want to walk. – chepner Dec 22 '20 at 19:13

4 Answers4

1
coordinates = [[[-15.418887, 28.180395], [-15.418887, 28.180395]],
               [[-15.794088, 28.018681], [-15.794088, 28.018681]]]

def recursively_add3(l):
    if isinstance(l, float):
        return l
    
    for index, inner_list in enumerate(l):
        inner_result = recursively_add3(inner_list)
        if inner_result is not None:
            l[index] = inner_result + 3
    
    return None

recursively_add3(coordinates)

which gives the result

[[[-12.418887, 31.180395], [-12.418887, 31.180395]]
, [[-12.794088, 31.018681], [-12.794088, 31.018681]]]
SiAce
  • 357
  • 3
  • 15
1

You can use a recursive function to handle the general case. Just check if you have a list and recurse, otherwise return the result of the addition:

def add_to_list(l, n):
    if not isinstance(l, list):
        return l + n
    return [add_to_list(sub, n) for sub in l]
   
coordinates = [[[-15.418887, 28.180395], [-15.418887, 28.180395]],[[-15.794088, 28.018681], [-15.794088, 28.018681]]]

add_to_list(coordinates, 3)    
#[[[-12.418887, 31.180395], [-12.418887, 31.180395]], [[-12.794088, 31.018681], [[-12.794088, 31.018681]]]]

# A more general case:
add_to_list([1, [2, [5, [6]]], 3], 2)
# [3, [4, [7, [8]]], 5]

# Degenerate cases
add_to_list([], 2)
# []
add_to_list(5, 2) 
# 7

This assumes that your nested data will either be numbers or lists.

Mark
  • 90,562
  • 7
  • 108
  • 148
1

General map approach to apply a function only to the innermost elements of a randomly deeply nested list:

def map_nested(fnc, lst):
    if not isinstance(lst, list):
        return fnc(lst)
    return [map_nested(fnc, x) for x in lst]
    # or for in-place mutation:
    # lst[:] = (map_nested(fnc, x) for x in lst)
    # return lst

add3 = lambda x: x+3

map_nested(add3, coordinates)
# [[[-12.418887, 31.180395], [-12.418887, 31.180395]], 
#  [[-12.794088, 31.018681], [-12.794088, 31.018681]]]
user2390182
  • 72,016
  • 6
  • 67
  • 89
  • Is this more efficient than recursive methods implemented by @SiArce or @`Mark Meyer`? – Angel Dec 22 '20 at 19:17
  • Efficiency is the same. It is just more reusable as it provides a way to apply any function (not just one that adds 3 or n) at an arbitrary nesting level. I find it more readable, too, as the `map_nested` focuses solely on its traversal task. – user2390182 Dec 22 '20 at 19:20
  • @Ángel, Another difference is that my result is in place, the other 2 return a new list – SiAce Dec 22 '20 at 19:25
  • MarkMeyer's and mine, do create and return a new list object, while SiAce mutates the existing one. – user2390182 Dec 22 '20 at 19:25
  • @SiAce Yup, was just pointing that out and added an in-place alternative to my approach. – user2390182 Dec 22 '20 at 19:26
0

You are using a 3D vector (lists of lists of lists) of coordinates right? Then your loop should be triple to access to all the variables on that 3D vector.

for x in list: #x is a list of lists
  for y in x: #y is a list
    for z in y: #z is a pair of coordinates
      #Your code here
  • As I said, In my case the length of the list is variable so it is not guaranteed to be 3D vector, however thank you very much for your response. – Angel Dec 22 '20 at 19:15
  • In that case, you can use this: for x in range(0, lengh(list)): list[x] is the way to access your elements That still allows to triple loop because if your list is empty, it will just ignore the loop – juan villarejo Dec 22 '20 at 19:38