zakparks31191
zakparks31191

Reputation: 937

Sorting a list containing lists

I have an algorithm that generates a list containing an unknown number of sublists, with each sublist having an unknown number of string elements as well as one floating point number. I need these sublists sorted inside of the main list according to this float. Also, the order of the strings in the sublists are not be be rearranged.

I currently have this running through a chunk of code (linked below) that sorts it using a dict. I am getting KeyErrors as you can see. I haven't worked with dicts before, so im not sure where to go from here. If there is a better way then a dict im open to that too. http://ideone.com/wr8UA

The floats are not sequential, im not sure how big of a deal this is using the method i have. Meaning, numbers will occasionally be skipped (in the example list in Ideone they are 1.0, 2.0, 4.0; skipping 3.0 to simulate this situation at runtime). They also arent in any specific location in the sublists, hence all the for loops searching for them.

Hopefully this is clear, i tried asking it before and got downvotes instead of questions about what was confusing to people. Let me know if something is amiss. Thanks everyone!

Edit: Code in the body as requested:

listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]] 

dictionary={}
for sub_list in listed:
    for value in sub_list:
        if isinstance(value,float):
            dictionary[str(value)]=sub_list
        else:
            pass
ordered_list=[]
    for i in range(1,len(listed)+1):
    if dictionary[str(i)]:
        ordered_list.append(dictionary[str(i)])

for sub_list in ordered_list:
    print sub_list

Upvotes: 3

Views: 517

Answers (5)

Estarius
Estarius

Reputation: 1219

Your error comes because there is no '1' element in your code. It is actually '1.0' (since it is a float), doing this would make the code work:

for i in range(1,len(listed)+1):
    if dictionary[str(float(i))]:
        ordered_list.append(dictionary[str(float(i))])

However, this is far from being a good way to do what you are trying to do in my opinion and many people gave good advices for alternatives.

Upvotes: 0

shiva
shiva

Reputation: 2770

>>> listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]]
>>> listed
[['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ'], ['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ'], ['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0]]
>>> dictionary ={}
>>> for index,sub_list in enumerate(listed):
    for value in sub_list:
        if isinstance(value,float):
            dictionary[value]=index
        else:
            pass


>>> dictionary
{1.0: 2, 2.0: 0, 3.0: 1}
>>> it = sorted(dictionary.items())
>>> it
[(1.0, 2), (2.0, 0), (3.0, 1)]
>>> ordered_list = []
>>> for item in it:
    ordered_list.append(listed[item[1]])


>>> ordered_list
[['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0], ['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ'], ['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ']]
>>> 

Upvotes: 0

Martijn Pieters
Martijn Pieters

Reputation: 1121484

The sort method has a handy key keyword argument, that let's you specify a function to call to determine on what information a list should be sorted.

Sorting your lists is as easy as writing a function that returns the float value contained in each sub list:

def sortOnFloat(sublist):
    return [v for v in sublist if isinstance(v, float)]

Note that I simply return a list of all the float values; much easier than having to return just one. This'll work even if there are 0 float values in the sublist.

Sort your list like this:

listed.sort(key=sortOnFloat)

I've cloned your example and updated it with the above method: http://ideone.com/u8ufK

Output generated:

['1 BW', '1AW AS', '3E FZ', '1BWAK', 'POK', 'TESTK', '1-2EHZ', '2E AK', 1.0]
['1 NWZ', '1 RWZ', '2 NWZ', '2 RWZ', '1E HZ', '1W HZ', '1-2EHZ', 2.0, '2W HZ']
['1 NWZ', '1W HZ', '3E FZ', 'SNOK', 'POK', 3.0, '1-2EHZ', '2E AK', '2W HZ']

Note that the .sort() method sorts the list in-place. You can also use the sorted() function to generate a new list that has been sorted; it takes the same argument:

orderedlist = sorted(listed, key=sortOnFloat)

but note that in-place sorting is always faster.

Upvotes: 9

sloth
sloth

Reputation: 101042

Create a function to extract the key on which you want to sort, and call sorted.

listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]] 

def get_key(l):
    return next(e for e in l if type(e) is float)

print sorted(listed, key=get_key)

Upvotes: 2

heltonbiker
heltonbiker

Reputation: 27575

You get an error because the numbers in the lists are floats, but you look for keys using integers:

listed = [ ["1 NWZ", "1 RWZ", "2 NWZ", "2 RWZ", "1E HZ", "1W HZ", "1-2EHZ", 2.0, "2W HZ"],
["1 NWZ", "1W HZ", "3E FZ", "SNOK", "POK", 3.0, "1-2EHZ", "2E AK", "2W HZ"],
["1 BW", "1AW AS", "3E FZ", "1BWAK", "POK", "TESTK", "1-2EHZ", "2E AK", 1.0]]

dictionary={}
for sub_list in listed:
    for value in sub_list:
        if isinstance(value,float):  #### you look for floats
            dictionary[str(value)]=sub_list   ### the key is created as string
        else:
            pass
ordered_list=[]
for i in range(1,len(listed)+1):   ### this is a range of INTS!!!!
    if dictionary[str(i)]:
        ordered_list.append(dictionary[str(i)])  #### str(i) is '1', not '1.0' 

for sub_list in ordered_list:
    print sub_list

I can only think this is not good code. In the first place, there shouldn't be strings and numbers mixed inside the same lists. If you create that lists, I suggest you to use a dict, like for example this:

listitem = {'number': 2.0, 'strings': ['1 NHZ', '1 RWZ', 'TESTK']}

Hope this helps!

Upvotes: 0

Related Questions