Search code examples
pythonlistsortedlist

How to sort list by using specific rules


Hi I have complicated data objects that I want to sort through s. Simplified version below:

class Data(object):
    def __init__(self, s):
        self.s = s

Each of this data objects will be placed in specific category for easy use later. Simplified version again below

class DataCategory(object):
    def __init__(self, id1, id2, linked_data=None):
        self.id1 = id1
        self.id2 = id2
        self.ld = linked_data

I want to sort data below by their s number BUT There are few more rules. If one data object was used from first data collection I want to use one from second collection IF s number is same or lower. Here is what I get and what I want to achieve

# order I get
# [['p02g01r05', 5], ['p02g01r01', 4], ['p01g01r05', 4], ['p01g01r01', 3], ['p01g01r02', 2], ['p01g01r03', 2], ['p01g01r06', 2], ['p02g01r02', 2], ['p02g01r03', 2], ['p02g01r04', 2], ['p01g01r04', 1], ['p02g01r06', 1]]
# order I want
# [['p02g01r05', 5], ['p01g01r05', 4], ['p02g01r01', 4], ['p01g01r01', 3], ['p02g01r02', 2], ['p01g01r02', 2], ['p02g01r03', 2], ['p01g01r03', 2], ['p02g01r04', 2], ['p01g01r06', 2], ['p02g01r06', 1]], ['p01g01r04', 1]

This is what I created so far but I'm thinking that I'm going in wrong direction with this. List of indexes to replace is correct I think.

# Some data objects
p01g01r01 = Data(3)
p01g01r02 = Data(2)
p01g01r03 = Data(2)
p01g01r04 = Data(1)
p01g01r05 = Data(4)
p01g01r06 = Data(2)

p02g01r01 = Data(4)
p02g01r02 = Data(2)
p02g01r03 = Data(2)
p02g01r04 = Data(2)
p02g01r05 = Data(5)
p02g01r06 = Data(1)

p01g01 = DataCategory("01", "01", [])
p02g01 = DataCategory("02", "01", [])


# link data to data category
def ldtdc(dc):
    lst = []
    data = "p" + dc.id1 + "g" + dc.id2 + "r"
    for i in range(1, 7):
        if i < 10:
            lst.append(data + "0" + str(i))
        else:
            lst.append(data + str(i))
    return lst

p01g01.ld = ldtdc(p01g01)
p02g01.ld = ldtdc(p02g01)


# /@= This starts to get way too complicated fast ############################
def lstu(ag, dg):
    lst = []
    # data list of first collection
    dlofc = []
    # data list of second collection
    dlosc = []

    # for every data unit that exists in data collection
    for unit in ag.ld:
        # lst.append([unit, globals()[unit].s+10])
        lst.append([unit, globals()[unit].s])
        dlofc.append([unit, globals()[unit].s])

    for unit in dg.ld:
        lst.append([unit, globals()[unit].s])
        dlosc.append([unit, globals()[unit].s])

    # lambda function is used here to sort list by data value ([1] is index of the item)
    lst = sorted(lst, key=lambda x: x[1], reverse=True)
    # current index
    ci = 0

    previous_data = ["last data unit will be stored here", 0]
    # sorted list
    slst = []

    for unit in lst:
        try:
            next_data = lst[ci+1]
        except IndexError:
            next_data = ["endoflist", 0]
        if previous_data[0] == "last data unit will be stored here":
            pass
        elif previous_data[0][:6] == unit[0][:6]:
            if unit[0][:6] not in dlofc[0][0]:
                slst.append([unit[0], unit[1], ci])
            elif unit[0][:6] not in dlosc[0][0]:
                slst.append([unit[0], unit[1], ci])
            else:
                print "Error"

        previous_data = unit
        ci += 1

    print "slist below"
    print slst

    return lst
# \@= END #####################################################################


print p01g01.ld
print p02g01.ld


data_list = lstu(p01g01, p02g01)
print data_list

What is the quick and correct way to sort this data?


Solution

  • Found solution. New lstu function:

    # replaced lambda with normal function
    def get_key(item):
        return item[1]
    
    
    def lstu(ag, dg):
        # ag list
        agslst = []
        # dg list
        dgslst = []
    
        # for every unit in first data collection
        for unit in ag.u:
            agslst.append([unit, globals()[unit].s])
        # sorted first data collection list
        agslst = sorted(agslst, key=get_key, reverse=True)
        print agslst
    
        for unit in dg.u:
            dgslst.append([unit, globals()[unit].s])
        # 2nd collection sorted list
        dgslst = sorted(dgslst, key=get_key, reverse=True)
        print dgslst
    
        lst = []
        # last item
        li = ["Empty", 0]
    
        for item in range(0, len(agslst)+len(dgslst)+1):
            if agslst and dgslst:
                if agslst[0][1] == dgslst[0][1]:
                    if li[0][:6] == agslst[0][0][:6]:
                        li = dgslst.pop(0)
                        lst.append(li)
                    else:
                        li = agslst.pop(0)
                        lst.append(li)
    
                elif agslst[0][1] > dgslst[0][1]:
                    li = agslst.pop(0)
                    lst.append(li)
                else:
                    li = dgslst.pop(0)
                    lst.append(li)
    
        return lst
    

    In this way I fulfill earlier mentioned requirements for new (and final) list

    Output:

    [['p02g01r05', 5], ['p01g01r05', 4], ['p02g01r01', 4], ['p01g01r01', 3], ['p02g01r02', 2], ['p01g01r02', 2], ['p02g01r03', 2], ['p01g01r03', 2], ['p02g01r04', 2], ['p01g01r06', 2], ['p02g01r06', 1]], ['p01g01r04', 1]]
    

    I'm open for any optimization suggestions.