Vesper
Vesper

Reputation: 845

how to sort tuples of list with a special condition?

I have two list underdraw and rate. They both contain 20 elements.

underdraw = [0,20,23,0,23,0,0,0,55,4,3,10,0,0,0,0,23,45,56,0]
rate = [0,201,43,0,123,0,0,0,0,43,35,120,0,0,0,0,253,5,0,0]

I divided the underdraw list into two lists further underLimit and beyondLimit and the limit is 25.

underLimit = [i if i <= 25 else 0 for i in underdraw]
beyondLimit = [i if i > 25 else 0 for i in underdraw]

now I combined these two lists with the rate

combinedLimits1 = list(zip(underLimit, rate))
combinedLimits2 = list(zip(beyondLimit, rate))

Now there are 20 tuples inside these two lists combinedList1 and combinedList2. I want to catogorized them into 5 sets.

n = 5
x = [combinedLimits1[i:i + n] for i in range(0, len(combinedLimits1), n)]
y = [combinedLimits2[i:i + n] for i in range(0, len(combinedLimits2), n)]

If you print the blocks of x and y

x=[(0, 0), (20, 201), (23, 43), (0, 0), (23, 123)]#list1
  [(0, 0), (0, 0), (0, 0), (0, 0), (4, 43)]#list2
  [(3, 35), (10, 120), (0, 0), (0, 0), (0, 0)]#list3
  [(0, 0), (23, 253), (0, 5), (0, 0), (0, 0)]#list4

y=[(0, 0), (0, 201), (0, 43), (0, 0), (0, 123)]#list1
  [(0, 0), (0, 0), (0, 0), (55, 0), (0, 43)]#list2
  [(0, 35), (0, 120), (0, 0), (0, 0), (0, 0)]#list3
  [(0, 0), (0, 253), (45, 5), (56, 0), (0, 0)]#list4

Now I want to sort this x and y in increasing rate order and took the smallest 3 values from it and take only those values in comparison when THERE IS A VALUE IN UNDERDRAW. Expected output(for x): Smallest 3 rates(if there is no rate then just put 20 there)

[(23,43), (23, 123), (20, 201)]#list1
[(4,43), (0, 20), (0, 20)]#list2
[(3,35), (10, 120), (0, 20)]#list3
[(23,253), (0, 20), (0, 20)]#list4
y=
[(0, 20), (0, 20), (0, 20)]#list1
[(50, 0), (0, 20), (0, 20)]#list2
[(0, 20), (0, 20), (0, 20)]#list3
[(56, 0), (45, 5), (0, 20)]#list4

So basically it is sorting only when there is a value in underdraw and as I required 3 min values so, if there are no min 3 elements then just simple put rate = 20 there. Can someone please help?

Upvotes: 1

Views: 88

Answers (3)

Masklinn
Masklinn

Reputation: 42492

now I combined these two lists with the rate

combinedLimits1 = list(zip(underLimit, rate))
combinedLimits2 = list(zip(beyondLimit, rate))

Are you sure that makes sense? Since underdraw and rate are the same lengths I'd have assumed they matched, this is going to combine the first n rates with what's under the limit, and the first k rates with above (where n and k are the number of items respectively under and above the limit).

Now there are 20 tuples inside these two lists combinedList1 and combinedList2. I want to catogorized them into 5 sets.

That's just chunking though, not categorisation.

Now I want to sort this x and y in increasing rate order and took the smallest 3 values from it and take only those values in comparison when THERE IS A VALUE IN UNDERDRAW. Expected output(for x): Smallest 3 rates(if there is no rate then just put 20 there)

So... take the first 3 items with a non-zero underdraw (they all have a value) ordered by ascending rate, pad with (0, 20) to 3 items if necessary?

# remove entries with underdraw = 0, sort by rate
items = sorted(((d, r) for d, r in lst if d != 0), key=lambda item: item[1])
# we now have 0~5 items, cut down to size
items = items[:3]
# pad with however many (0, 20) items are missing to go to 3
items += [(0, 20)] * (3 - len(items))

Upvotes: 1

Bhavye Mathur
Bhavye Mathur

Reputation: 1077

# Code (edited) from geeksforgeeks.org/python-program-to-sort-a-list-of-tuples-by-second-item/
def sortTuple(tup):  
    tup.sort(key = lambda i: i[1])
    return tup  

# You can repeat this same thing for the y list
for index, sublist in enumerate(x):
    orderedSublist = sortTuple(sublist)

    for element in orderedSublist.copy():
        if element[1] == 0:
            orderedSublist.append(orderedSublist.pop(0))
            orderedSublist[-1] = (orderedSublist[-1][0], 20)  # You can't mutate (edit) tuples so we create a new one

    orderedSublist = orderedSublist[:3]  # Taking the smallest 3 elements (excluding 0s)
    x[index] = orderedSublist

The code is essentially going through every sublist in x and sorting that according to the second element of the tuple. This is sorted in a way that the 0s come at the beginning as well so we go through every element in the ordered list and shift all the tuples with the rate being 0 to the back.

Finally, we just take the first 3 elements and print out the list.

Upvotes: 1

MrNobody33
MrNobody33

Reputation: 6483

You could try this with filter and sorted:

underdraw = [0,20,23,0,23,0,0,0,55,4,3,10,0,0,0,0,23,45,56,0]
rate = [0,201,43,0,123,0,0,0,0,43,35,120,0,0,0,0,253,5,0,0]
underLimit = [i if i <= 25 else 0 for i in underdraw]
beyondLimit = [i if i > 25 else 0 for i in underdraw]
combinedLimits1 = list(zip(underLimit, rate))
combinedLimits2 = list(zip(beyondLimit, rate))
n = 5
x = [combinedLimits1[i:i + n] for i in range(0, len(combinedLimits1), n)]
y = [combinedLimits2[i:i + n] for i in range(0, len(combinedLimits2), n)]
newx=[sorted(list(filter(lambda y: y[0]!=0,ls)),key=lambda h: h[1]) for ls in x]
newx=[ls if len(ls)==3 else ls+[(0,20)]*(3-len(ls)) for ls in newx ]
newy=[sorted(list(filter(lambda y: y[0]!=0,ls)),key=lambda h: h[1]) for ls in y]
newy=[ls if len(ls)==3 else ls+[(0,20)]*(3-len(ls)) for ls in newy ]
print(newx)
print(newy)

Output:

newx
[[(23, 43), (23, 123), (20, 201)], [(4, 43), (0, 20), (0, 20)], [(3, 35), (10, 120), (0, 20)], [(23, 253), (0, 20), (0, 20)]] 

newy
[[(0, 20), (0, 20), (0, 20)], [(55, 0), (0, 20), (0, 20)], [(0, 20), (0, 20), (0, 20)], [(56, 0), (45, 5), (0, 20)]]

Upvotes: 1

Related Questions