[GIS] How to sort features in a layer using OGR/Python

gdalogrpython

How can I sort the features of an ogr layer by the values of a field?
I tried naive variations of

def sortlayer(ds, layer, field):
    lname = layer.GetName()
    lsort = ds.ExecuteSQL(b'select * from "{}" order by {}'.format(lname, field))
    ds.DeleteLayer(lname)
    ds.CopyLayer(lsort, lname)

but this either crashed or freezed.

Bonus points for a solution that doesn't change the order of layers in the datasource and/or that doesn't rely on unique layer names.

Actually the datasources are in-memory (memory-driver), and I may have up to 10 layers with up to 10.000 features over all.

Maybe it would be better not to use SQL but create an index as list, and then swap features around in the layer with Layer.GetFeature()/.SetFeature()?

Thanks, Redoute

Best Answer

I followed the second approach now and this seems to work, comments welcome:

def sortlayer(l, fd):
    # fids are unique, fids may be sorted or unsorted, fids may be consecutive or have gaps
    # don't care about semantics, don't touch fids and their order, reuse fids
    fids = []
    vals = []
    l.ResetReading()
    for f in l:
        fid = f.GetFID()
        fids.append(fid)
        vals.append((f.GetField(fd), fid))
    vals.sort()
    # index as dict: {newfid: oldfid, ...}
    ix = {fids[i]: vals[i][1] for i in xrange(len(fids))}

    # swap features around in groups/rings
    for fidstart in ix.keys():
        if fidstart not in ix: continue
        ftmp = l.GetFeature(fidstart)
        fiddst = fidstart
        while True:
            fidsrc = ix.pop(fiddst)
            if fidsrc == fidstart: break
            f = l.GetFeature(fidsrc)
            f.SetFID(fiddst)
            l.SetFeature(f)
            fiddst = fidsrc
        ftmp.SetFID(fiddst)
        l.SetFeature(ftmp)