views:

124

answers:

2

Good day code knights,

I have a tricky problem that I cannot see a simple solution for. And the history of the humankind states that there is a simple solution for everything (excluding buying presents)

Here is the problem:

I need an algorithm that takes multidimensional lists and a filter dictionary, processes them and returns lists based on the filters.

For example:

Bathymetry ('x', 'y')=(182, 149) #notation for (dimensions)=(size)
Chl  ('time', 'z', 'y', 'x')=(4, 31, 149, 182) 
filters {'x':(0,20), 'y':(3), 'z':(1,2), time:()} #no filter stands for all values

Would return:

readFrom.variables['Bathymetry'][0:21, 3]    
readFrom.variables['Chl'][:, 1:3, 3, 0:21]

I was thinking about a for loop for the dimensions, reading the filters from the filter list but I cannot get my head around actually passing the attributes to the slicing machine.

Any help much appreciated.

+2  A: 

Something like the following should work:

def doit(nam, filters):
    alldims = []
    for dimname in getDimNames(nam):
      filt = filters.get(dimname, ())
      howmany = len(filt)
      if howmany == 0:
        sliciflt = slice()
      elif howmany == 1:
        sliciflt = filt[0]
      elif howmany in (2, 3):
        sliciflt = slice(*filt)
      else:
        raise RuntimeError("%d items in slice for dim %r (%r)!"
                           % (howmany, dimname, nam))
      alldims.append(sliciflt)


return readFrom.variables[nam][tuple(alldims)]
Alex Martelli
Aaah, so there IS such a thing as a slice object. Just what I needed, thank you very much.
Rince
+2  A: 

I'm not sure I understood your question. But I think the slice object is what you are looking for:

First instead of an empty tuple use None to include all values in time

filters=  {'x':(0,20), 'y':(3), 'z':(1,2), 'time':None}

Then build a slice dictionary like this:

d = dict(
        (k, slice(*v) if isinstance(v, tuple) else slice(v))
        for k, v in filters.iteritems()
    )

Here is the output:

{
    'y': slice(None, 3, None),
    'x': slice(0, 20, None),
    'z': slice(1, 2, None),
    'time': slice(None, None, None)
}

Then you can use the slice objects to extract the range from the list

Nadia Alramli
Thank you!Too bad I cannot accept more than I answer. Yours is very elegant while Martellis is easier to understand. Being a newbie I will go for the simpler one.
Rince