Reputation: 937
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
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
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
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
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
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