Python sorting an order of a list based on a string

Thread Starter

zazas321

Joined Nov 29, 2015
936
Hello. I am developing a python program for my application. Python receives multiple messages with different serial codes, for every serial code, I assign it a priority value as following:

The priorities are assigned based on the first 2 characters of its serial number. I want "AN" serial number to always go before "PS" and etc..
Code:
def Assign_priorities(Serial):
    #Priority list
    # PS - #2
    # AN - #1
    # PA - always last
    if(Serial[0:2] == "AN"):
        print("PRIORITY 1")
        priority = 1
        return priority
    elif(Serial[0:2] == "PS"):
        print("PRIORITY 2")
        priority = 2
        return priority
    elif(Serial[0:2] == "PA"):
        print("PRIORITY 4")
        priority = 4
        return priority
    else:
        print("PRIORITY 3")
        priority = 3
        return priority

[code]


after I retrun the priority, I fill an item list with following data:
[code]
item.append(Item(Device,Quantity,Serial,Priority))
Now my item list will contain information about device, quantity, serial and the priority. For example it might look like:
Code:
item[0] = ['device1', '10', CB123122, 3];
item[1] = ['device5, '20', EX000022, 4];
item[2] = ['device3', '30', PS123122, 2];
item[3] = ['device4', '40', CB120022, 3];
item[4] = ['device2', '20', AB000122, 1];
Now, the main task is to sort this list and create an array based on the priority numbers. For my sorted array, I only care about the device name. If more than 1 item is assigned to same priority, then just prioritize random. For the example above, I need to sort it as following:

sorted_list = [device2,device3,device1,device4,device5]

I have written a function :
Code:
def sort_picking_order(item_list):
    global sorted_list
    sorted_list = []
    #pick_order = 0
    # LOOK FOR HIGHEST PRIORITY
    for i in range(len(item_list)):     
        if(item_list[i].Priority == 1):
            print("Highest priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("Highest priority item is not found in the list")
    
    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)       
        if(item_list[i].Priority == 2):
            print(" 2nd Highest priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("2nd Highest priority item is not found in the list")
            
    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)       
        if(item_list[i].Priority == 3):
            print(" 3rd  priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("3rd priority item is not found in the list")
            

    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)       
        if(item_list[i].Priority == 4):
            print(" last  priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("last priority item is not found in the list")
            
    print("sorted list",sorted_list)
I have multiple for loops that go through the whole list . It starts from the highest priority and then goes down. I am wondering whether there is a more efficient way to sort it based on the priority values other than running for loop multiple times which seems like a very inefficient way.
 

Ajith-N

Joined Sep 14, 2020
31
Well, that's not typical python idiom. Take a look at the 'sorted' method all "iterables" implement. List is an iterable, so you can go this way. The signature is:
iterable. sorted(iterable, *, key=None, reverse=False)
where key is a custom function you can provide. That means you can implement non-lexicographic sort orders, or arbitrary orderings as desired.
Documentation at https://docs.python.org/3.8/library/functions.html#sorted
 

hrs

Joined Jun 13, 2014
394
Yes, use sorted(). Also, don't use globals, just return sorted_list.
And don't do this:
Code:
for i in range(len(item_list)):
If you must have the index do this:
Code:
for i, item in enumerate(item_list):
but since you don't need the index here you can just do:
Code:
for item in item_list:
But with sorted() you don't need the loops.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Thanks for poiting me in the right direction. After reading the documentation I still cannot fully figure out how to implement a sorted() function to sort in ascending order based on an object inside a list.

I have an class name Item
Code:
class Item:
    def __init__(self,Device,Quantity,Serial,Priority):
        self.Device = Device
        self.Serial = Serial
        self.Quantity = Quantity
        self.Priority = Priority
Then inside my program, I create an item array and assign it to class variable as following:
Code:
item.append(Item(Device,Quantity,Serial,Priority))
So in the end, my item array looks like:
Code:
item[0] = ['device1', '10', CB123122, 3];
item[1] = ['device5, '20', EX000022, 4];
item[2] = ['device3', '30', PS123122, 2];
item[3] = ['device4', '40', CB120022, 3];
item[4] = ['device2', '20', AB000122, 1];
So now I have an array which contains a list. At this point I just need to sort it based on the last variable of list which is Priority. And I the result I need is just the device names sorted in order.
Code:
def sorting2(item_list):
    sorted_list2=sorted(item_list, key = lambda x: x[3], reverse=False)
    print(sorted_list2)
I have written the above function and to my understanding, passing lambda x: x[3] to the key argument will sort it based on the 4th value inside a list which in my case is Priority.

However, the program returns me an error:
Code:
    sorted_list2=sorted(item_list, key = lambda x: x[3], reverse=False)
TypeError: 'Item' object is not subscriptable
I have done this according to the example below:
Code:
# Python code to sort the tuples using second element  
# of sublist Function to sort using sorted() 
def Sort(sub_li): 
  
    # reverse = None (Sorts in Ascending order) 
    # key is set to sort using second element of  
    # sublist lambda has been used 
    return(sorted(sub_li, key = lambda x: x[1]))     
  
# Driver Code 
sub_li =[['rishav', 10], ['akash', 5], ['ram', 20], ['gaurav', 15]] 
print(Sort(sub_li))
Which I found here:
https://www.geeksforgeeks.org/python-sort-list-according-second-element-sublist/
 
Last edited:

hrs

Joined Jun 13, 2014
394
Then inside my program, I create an item array and assign it to class variable as following:
Code:
item.append(Item(Device,Quantity,Serial,Priority))
I don't think this is actual code and I think it will throw an error.

So in the end, my item array looks like:
Code:
item[0] = ['device1', '10', CB123122, 3];
item[1] = ['device5, '20', EX000022, 4];
item[2] = ['device3', '30', PS123122, 2];
item[3] = ['device4', '40', CB120022, 3];
item[4] = ['device2', '20', AB000122, 1];
Are you sure about that? I think you'll get a list (not array) of Item object. Did you try printing some to console?

However, the program returns me an error:
Code:
    sorted_list2=sorted(item_list, key = lambda x: x[3], reverse=False)
TypeError: 'Item' object is not subscriptable
See above.
Do you have more things in you Item class or just those 4 atributes? If just these 4 atributes, consider using a list and your sorted() will work.

Also have a look at dictionaries. You can do nice things with them.
Code:
def assign_priorities(serial):
    priorities = {'AN': 1, 'PS': 2, 'PA': 4}
    try:
        prio = priorities[serial[:2]]
    except KeyError:
        prio = 3
    return prio
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Hey.

item.append(Item(Device,Quantity,Serial,Priority))

The above is an actual line from my code and it works fine.

Before that line, I create an empty array like that:
item = []
and I fill this array
with the code:
item.append(Item(Device,Quantity,Serial,Priority))

Now I can access the individual objects of a class like that:
Code:
print(item[0].Device)
print(item[1].Serial
print(item[3].Priority
and etc.


So my item array will contain an information about class. I am not sure how this is called. Is that not a list?
 

hrs

Joined Jun 13, 2014
394
Ok, but then first you need something like
Code:
Device = 'bla'
Quantity =34123
...
or it will throw an error.

Again, do you need it to be an Item class? What you have now is a list of Item objects (instead of a list of lists). Your Item objects are not subscriptable and therefore sorted() will not work. Lists are subscriptable.
 

Thread Starter

zazas321

Joined Nov 29, 2015
936
Ok, but then first you need something like
Code:
Device = 'bla'
Quantity =34123
...
or it will throw an error.

Yes I have the Deviec, Quantity, Serial and Priority data before calling this function

Again, do you need it to be an Item class? What you have now is a list of Item objects (instead of a list of lists). Your Item objects are not subscriptable and therefore sorted() will not work. Lists are subscriptable.
Yes I have the Device, Quantity, Serial and Priority data before calling this function. It comes from reading the database. My mistake from not describing the situation initially. See below for more info


The reason why I save it as an Item class is because I thought its going to be easy to understand and keep track of this Item data.

The Item data comes from mysql database that I read. I have a table on the database that gets updated from other sources. The database contains 3 rows of data: Device,Quantity,Serial. The Priority is being calculated and assigned based on the Serial number first 2 digits as I have mentioned in my first post


What other options would you suggest me instead of using an Item class? After I read my database and sort out the priorities. I just need to make an array of items that would be sorted based on priorities. I dont exactly need it to be a an item class I just didint know any other way
 

hrs

Joined Jun 13, 2014
394
I would use a list. If you change
Code:
item.append(Item(Device,Quantity,Serial,Priority))
to
Code:
item.append([Device, Quantity, Serial, Priority])
that should do it.
 

ApacheKid

Joined Jan 12, 2015
1,533
Hello. I am developing a python program for my application. Python receives multiple messages with different serial codes, for every serial code, I assign it a priority value as following:

The priorities are assigned based on the first 2 characters of its serial number. I want "AN" serial number to always go before "PS" and etc..
Code:
def Assign_priorities(Serial):
    #Priority list
    # PS - #2
    # AN - #1
    # PA - always last
    if(Serial[0:2] == "AN"):
        print("PRIORITY 1")
        priority = 1
        return priority
    elif(Serial[0:2] == "PS"):
        print("PRIORITY 2")
        priority = 2
        return priority
    elif(Serial[0:2] == "PA"):
        print("PRIORITY 4")
        priority = 4
        return priority
    else:
        print("PRIORITY 3")
        priority = 3
        return priority

[code]


after I retrun the priority, I fill an item list with following data:
[code]
item.append(Item(Device,Quantity,Serial,Priority))
Now my item list will contain information about device, quantity, serial and the priority. For example it might look like:
Code:
item[0] = ['device1', '10', CB123122, 3];
item[1] = ['device5, '20', EX000022, 4];
item[2] = ['device3', '30', PS123122, 2];
item[3] = ['device4', '40', CB120022, 3];
item[4] = ['device2', '20', AB000122, 1];
Now, the main task is to sort this list and create an array based on the priority numbers. For my sorted array, I only care about the device name. If more than 1 item is assigned to same priority, then just prioritize random. For the example above, I need to sort it as following:

sorted_list = [device2,device3,device1,device4,device5]

I have written a function :
Code:
def sort_picking_order(item_list):
    global sorted_list
    sorted_list = []
    #pick_order = 0
    # LOOK FOR HIGHEST PRIORITY
    for i in range(len(item_list)):    
        if(item_list[i].Priority == 1):
            print("Highest priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("Highest priority item is not found in the list")
   
    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)      
        if(item_list[i].Priority == 2):
            print(" 2nd Highest priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("2nd Highest priority item is not found in the list")
           
    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)      
        if(item_list[i].Priority == 3):
            print(" 3rd  priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("3rd priority item is not found in the list")
           

    for i in range(len(item_list)):
        #print("Serial=",item_list[i].Serial)      
        if(item_list[i].Priority == 4):
            print(" last  priority item found")
            sorted_list.append(item_list[i].Device)
            #pick_order = pick_order + 1
        else:
            print("last priority item is not found in the list")
           
    print("sorted list",sorted_list)
I have multiple for loops that go through the whole list . It starts from the highest priority and then goes down. I am wondering whether there is a more efficient way to sort it based on the priority values other than running for loop multiple times which seems like a very inefficient way.
This is trivial to do if it were C# because that supports LINQ. But LINQ is a general purpose concept and it seems there is a library around for Python:

https://pypi.org/project/py-linq/

I know very little about Python, but saw right away that your problem is well suited to LINQ.
 

ApacheKid

Joined Jan 12, 2015
1,533
Using LINQ operators and C# the solution would look a bit like this:

Code:
sorted = item.OrderBy(x => x.Priority);
The expression "x => x.Priority" is actually a tiny function that has no name, called "lambda" functions in C#.

The choice of the name "x" is arbitrary, it's just the name of a variable that will be passed in for every item in the source list.

Python supports lambdas natively so this is likely what the PyLinq library uses.

Whenever you have sequences of data (lists, arrays whatever) that needs to be sorted, filtered, converted etc LINQ is very powerful it is based on functional programming languages which excel in solving these kinds of problems.
 
Last edited:
Top