This is faster than your original code, and easier to read IMO:
data = [
'Option A',
'Option B',
'Blabla',
'Some text'
]
idata = list(enumerate(data)) # add indexes to uniquely identify items
sdata = sorted(idata, key=lambda x: x[1]) # sort the items by label
flt_neworder = [sdata.index(x) for x in idata] # find the position to move to
Results with timeit
:
orig: 12.3757910728
origmod: 7.85222291946
orignew: 6.15745902061
rewrite: 6.31552696228
(origmod is like your original code, but without the Item
class as it doesn't seem like you use it; orignew is your one-liner)
Your one-liner is slightly faster, but I think harder to read.
Ok, I'll include my full test code this time. I moved the Item
creation out of orig
since you're only creating those to mimic the real world data. In addition to orig3
(your new code) and rewriteop
(rewrite
with operator.itemgetter
), I added an extra test rewriteuniq
on the off chance that your strings will be unique.
Results:
orig: 7.641715765
origmod: 7.38071417809
orignew: 5.82565498352
orig3: 5.67061495781
rewrite: 5.95284795761
rewriteop: 5.61896586418
rewriteuniq: 1.90719294548
Code:
import operator
from timeit import timeit
data = [
'Option A',
'Option B',
'Blabla',
'Some text',
]
desired_output = [1, 2, 0, 3]
class Item:
def __init__(self, label):
self.label = label
col = [Item(d) for d in data]
def orig():
flt_neworder = [
x[1] for x in sorted(
zip(
[x[0] for x in sorted(enumerate(col), key=lambda x: x[1].label)],
range(len(col))
)
)
]
assert flt_neworder == desired_output
def origmod():
flt_neworder = [
x[1] for x in sorted(
zip(
[x[0] for x in sorted(enumerate(data), key=lambda x: x[1])],
range(len(data))
)
)
]
assert flt_neworder == desired_output
def orignew():
flt_neworder = list({k: i for i, (k, v) in enumerate(sorted(enumerate(data), key=operator.itemgetter(1)))}.values())
assert flt_neworder == desired_output
def orig3():
flt_neworder = [None] * len(col)
for j, (_, i) in enumerate(sorted(zip((item.label for item in col), range(len(col))))): flt_neworder[i] = j
assert flt_neworder == desired_output
def rewrite():
idata = list(enumerate(data))
sdata = sorted(idata, key=lambda x: x[1])
flt_neworder = [sdata.index(x) for x in idata]
assert flt_neworder == desired_output
def rewriteop():
idata = list(enumerate(data))
sdata = sorted(idata, key=operator.itemgetter(1))
flt_neworder = [sdata.index(x) for x in idata]
assert flt_neworder == desired_output
def rewriteuniq():
sdata = sorted(data)
flt_neworder = [sdata.index(x) for x in data]
assert flt_neworder == desired_output
for fn in (orig, origmod, orignew, orig3, rewrite, rewriteop, rewriteuniq):
print fn.__name__ + ':', timeit(fn)