0

EDIT : This question is a complete mess. The answers actually give a better explanation of the question than the question itself.

I have a list of objects.

['BODY.H','BODY.VL','WHL0.H','BODY.M']

But this list will never be in the correct order I want to be. I want to have these strings ordered in a way such as this

['BODY.H','BODY.M','BODY.VL','WHL0.H']

Where BODY.H will always be at index 0, BODY.M will always be at index 1, etc.

Is there a way I can sort a list based on a predicate list of sorts? (e.g. ['BODY.H','BODY.M']). I haven't tried anything yet because I have no idea on where to start with this.

aaro4130
  • 115
  • 1
  • 9
  • This isn't enough information, it may be good to include the code you're using with the actual result and the desired behavior. Also, see [How to create a Minimal, Complete, and Verifiable example](http://stackoverflow.com/help/mcve) – Jared Goguen Feb 28 '16 at 06:10
  • The problem is I have no idea of where to start in this. – aaro4130 Feb 28 '16 at 06:12
  • And nobody is going to be able to help you unless you explain your problem more clearly... – Jared Goguen Feb 28 '16 at 06:14
  • I've just edited it in a manner that is hopefully clearer. I have trouble structuring speech/text posts, my apologies if it was too unclear. – aaro4130 Feb 28 '16 at 06:15
  • it looks like from your example that you can just order them alphabetically ... ``sorted(whatever_variable_name_your_list_has)``. Also lists are ordered when you append to them. Would it be possible to just insert them in the correct order? Or use nested lists if you want to keep associated objects seperate. – MSeifert Feb 28 '16 at 06:20
  • Oh wow ,I used some bad strings as examples haha. It'd be non-alphabetical in cases where the order would have to be `['H','M','L','BREAK01','BREAK02'] and so on – aaro4130 Feb 28 '16 at 06:22
  • so you want to sort by the "extension" after the ``.``? Or nested sorted like first sort ``BODY`` and the sort these by the extension, ...? – MSeifert Feb 28 '16 at 06:26
  • The objects I'm sorting are being exported to a file, and the program reading the file expect the objects to be written in a specific order. With H coming first, M coming next, L coming after that, BREAK01-99 coming after that.. So what I'm trying to do is basically reorder a list where these are all jumbled up inside. E.g. H L M BREAK01 VL would be reordered to H M L VL BREAK01. If that makes sense. – aaro4130 Feb 28 '16 at 06:28
  • Not really, in your post there is just ``['BODY.H','BODY.M','BODY.VL','WHL0.H']`` and no ``H M L VL BREAK01``. Maybe make your example really close to reality (within limits) and show pre- and postconditions and we might help you but so far we can only guess. – MSeifert Feb 28 '16 at 06:35

2 Answers2

1

(You've changed your question to wanting to do it with strings instead of with objects, so this example is with strings.)

Use the index of each string in predicate list to provide the key on which to sort your given list:

>>> wanted_order = ['BODY.H', 'BODY.M', 'BODY.VL', 'WHL0.H']
>>> got_list = ['WHL0.H', 'BODY.H', 'BODY.VL', 'BODY.VL', 'WHL0.H', 'BODY.M']
>>> sorted(got_list, key=lambda s: wanted_order.index)
['BODY.H', 'BODY.M', 'BODY.VL', 'BODY.VL', 'WHL0.H', 'WHL0.H']

Note that I've added a few extra duplicate items in got_list to show how it would work with generic input and more than one of each.

Btw, if there will always be just these 4 objects, why not just create a list with these 4?

Also, if a string is missing from your predicate, you'll get an error. So maybe put that in a function (rather than a lambda) and catch that error if it occurs, and return another value.

Edit:

For the object version of what you wanted, you would use s.name for the key and predicate (and of course, wanted_order has the names of objects):

>>> sorted(got_list, key=lambda s: wanted_order.index(s.name))

Edit 2:

To handle items in got_list which don't have a 'name' in wanted_order:

>>> def predicated_key(item):
...     wanted_order = ['BODY.H', 'BODY.M', 'BODY.VL', 'WHL0.H']
...     # put wanted_order in global scope if you prefer instead of here
...     try:
...         return wanted_order.index(item)  # or item.name in your case
...     except ValueError:
...         return len(wanted_order)  # since this will be higher than the
...                                   # index of the any item on the list
...
>>> got_list = ['WHL0.H', 'BODY.H', 'something', 'BODY.VL',
...             'something else', 'BODY.VL', 'WHL0.H', 'BODY.M']
>>> sorted(got_list, key=predicated_key)
['BODY.H', 'BODY.M', 'BODY.VL', 'BODY.VL', 'WHL0.H', 'WHL0.H', 'something', 'something else']
aneroid
  • 12,983
  • 3
  • 36
  • 66
  • What happens here if I provide a name in the `got_list` that doesn't exist in `wanted_order`? – aaro4130 Feb 28 '16 at 07:04
  • 1
    That's already addressed in my answer. _"Also, if a string is missing from your predicate, you'll get an error. So maybe put that in a function (rather than a lambda) and catch that error if it occurs, and return another value."_ So in this case, you could just return a really high value or `len(predicate_list) `. So they all get put at the end and in the same order they were in your original list. – aneroid Feb 28 '16 at 07:09
  • Didn't notice that also applied to the edited version of the answer. – aaro4130 Feb 28 '16 at 07:10
0

Sorry for the confusion on the initial question. When I put some thought into it, I ended up figuring it out :)

def reorder_object_list(lst,pred):
return_list = [None] * len(pred)
for v in lst:
    try:
        return_list[pred.index(v)] = v
    except:
        #not found in predicate list 
        return_list.append(v)
return [x for x in return_list if x != None]

list = ["HLIGHT_L","BODY_H","BODY_VL","TLIGHT_L","BODY_M"]
pred = ["BODY_H","BODY_M","BODY_VL","HLIGHT_L","TLIGHT_L"]
reordered = reorder_list(list,pred)
for v in reordered:
    print(v)
aaro4130
  • 115
  • 1
  • 9
  • The issue with your example is that if your predicate list is the same as the list you have, then you can just create the list directly. If you want a more generic way to sort on the predicate list, see my answer below/above. – aneroid Feb 28 '16 at 06:52
  • I realized it just after I posted the answer, Updated to something that should fix that – aaro4130 Feb 28 '16 at 06:54
  • That still doesn't actually work because in the line `return_list[pred.index(v.name)]`, if the same object appears multiple times, it overwrites itself at that index, since it is same index in your predicate list. So if there were 3 `"BODY_H"` objects, your return list would only have one. – aneroid Feb 28 '16 at 06:58
  • Because I'm using it with the Blender API, the same object will never appear multiple times. So in this case that isn't an issue for me. – aaro4130 Feb 28 '16 at 06:58