How to sort items in Qtreeview in pyqt5? - python

How to sort items in QTreeview by the following concepts ?
Ascending Order ( From A to Z, 0 to 9)
Descending Order ( From Z to A , 9 to 0)
Given Order or Original order by user ( From A to Z )
Reverse Order of Original Order ( From Z to A)
self.model_01 = self.model()
for i in range(self.model_01.rowCount()):
if self.itemData(i) is None:
self.setItemData(i, i)
...
def ascending_order(self):
self.model_01.setSortRole(Qt.DisplayRole)
self.model_01.sort(self.modelColumn(), Qt.AscendingOrder)
def descending_order(self):
self.model_01.setSortRole(Qt.DisplayRole)
self.model_01.sort(self.modelColumn(), Qt.DescendingOrder)
def given_order(self):
print("given order")
self.model_01.setSortRole(Qt.UserRole)
self.model_01.sort(self.modelColumn(), Qt.AscendingOrder)
def reverse_order(self):
print("reverse order")
self.model_01.setSortRole(Qt.UserRole)
self.model_01.sort(self.modelColumn(), Qt.DescendingOrder)
using this code , I can able to sort item in ascending order as well as in descending order in Qt.DisplayRole.
But in Qt.UserRole, I cant able to sort items.
How to sort items in ascending(Original order) or in reverse of original order ?

Related

How would I check if a value is larger than nth value of list of tuples?

I'm looking to optimize this function:
cache = dict()
def user_rec (userID,nmf_matrix=nmf_matrix,topic_df=topic_df):
if userID in cache:
return cache[userID]
users=[]
for l in topic_df.loc[topic_df['user_id']==userID].index:
for j in range (nmf_matrix.shape[0]):
if topic_df.iloc[j].user_id != userID:
sim = np.dot(nmf_matrix[j,:],nmf_matrix[l,:])
users.append((topic_df.iloc[j].user_id,sim))
users.sort(key=lambda x: x[1], reverse=True)
top_users=[]
for top in users:
if top not in top_users:
top_users.append(top)
top_users = top_users[0:3]
cache[userID]=top_users
return [top[0] for top in top_users]
One part that I've identified as something that could be slimmed down is to just keep the list of as the top users while I'm calculating sim. ie. keep the tuple with the larger sim value
I'm not sure how I would go about doing this.
I've tried something like this with no success.
sim = np.dot(nmf_matrix[j,:],nmf_matrix[l,:])
if (all([users[1] for x in users]>sim)):
users = users
else:
users.append((topic_df.iloc[j].user_id,sim))
users.remove(min())

Moving item in lists with functions

My code runs but I'm expecting my orders to follow 3,2,1.
To my knowledge pop() takes the last entry and returns it.
So on my last call move_to_old_orders(made_orders) it returns in the list 1,2,3.
If you look in the output it goes from 3,2,1 / 3,2,1 / 1, 2, 3.
The print statements at the end are for me to verify the list is empty and has moved.
Code:
unmade_orders = ['order 1' , 'order 2', 'order 3']
made_orders = []
old_orders = []
def make_orders(unmade_orders, made_orders):
''' To make an order '''
while unmade_orders:
current_order = unmade_orders.pop()
print("Order Processing: " + current_order.title() + ".")
made_orders.append(current_order)
def print_orders(made_orders):
''' To print an order '''
for made_order in made_orders:
print("Order Processed: " + made_order.title() + ".")
make_orders(unmade_orders, made_orders)
print_orders(made_orders)
def move_to_old_orders(made_orders):
while made_orders:
current_order_1 = made_orders.pop()
print("Moving Order To Old Orders: " + current_order_1.title() + ".")
old_orders.append(current_order_1)
move_to_old_orders(made_orders)
print(unmade_orders)
print(made_orders)
print(old_orders)
Output:
Order Processing: Order 3.
Order Processing: Order 2.
Order Processing: Order 1.
Order Processed: Order 3.
Order Processed: Order 2.
Order Processed: Order 1.
Moving Order To Old Orders: Order 1.
Moving Order To Old Orders: Order 2.
Moving Order To Old Orders: Order 3.
Your function make_orders() is appending the list make_orders = [] in this make_orders = ["order 3","order 2","order 1"] kind of format as it should be, 'cause it's the nature of append()
That's why when you call the function move_to_old_orders()
It starts from the last element which is order 1
That's why you are getting the output of 1 2 3

Check if list is sorted in either ascending or descending order in one pass

Is there a way to check if a list is sorted either in ascending or descending order in one pass?
From this answer, I modified to also support descending order check, so my code now looks like this, is there a way to check this without having to use two for loops?
def is_sorted(check):
current = check
forwarded = check[1:]
ascending_check = all(i<=j for i, j in zip(current, forwarded))
descending_check = all(i>=j for i, j in zip(current, forwarded))
return ascending_check or descending_check
numbers = list(range(1, 10))
print(is_sorted(numbers))
reverse_numbers = list(range(10, 0, -1))
print(is_sorted(reverse_numbers))
not_sorted = [1, 3, 2, 4, 5]
print(is_sorted(not_sorted))
This would work:
def is_sorted(check):
asc = desc = True
i, L = 0, len(check)
while (i < (L-1)) and (asc or desc):
if check[i] < check[i+1]:
desc = False
elif check[i] > check[i+1]:
asc = False
if not (asc or desc):
break
i += 1
if asc and desc:
return "Ascending and Descending"
elif asc:
return "Ascending"
elif desc:
return "Descending"
else:
return "Not ascending and not descending"
Tests:
print (is_sorted([1, 2, 3]))
print (is_sorted([3, 2, 1]))
print (is_sorted([1, 2, 3, 2, 1]))
print (is_sorted([1, 1, 1]))
Output:
Ascending
Descending
Not ascending and not descending
Ascending and Descending
You can examine the first two elements, then return True if the entire list has the same ordering as those two. You have to also take into account the possibility that there is a tie at the beginning, and that the entire list only contains the same values throughout.
def is_sorted(check):
ascending = True
descending = True
previous = check[0]
for item in check[1:]:
if ascending and item < previous:
ascending = False
if descending and item > previous:
descending = False
if not ascending and not descending:
return False
previous = item
return True
Demo: https://ideone.com/YjBB9T
You could check pairs of consecutive elements, keep track of whether the first pair that is not == is < or >, and check that all the other pairs have the same relation (if not equal):
def is_sorted(lst):
asc = None
for i in range(len(lst)-1):
a, b = lst[i], lst[i+1]
if a == b:
continue
if asc is None:
asc = (a < b)
if (a < b) != asc:
return False
return True
That's a bit verbose, but you could also make it shorter with next and all, using a shared zip iterator for both so the entire list is iterated only once.
def is_sorted(lst):
pairs = zip(lst, lst[1:])
asc = next((a < b for a, b in pairs if a != b), None)
return asc is None or all((a < b) == asc for a, b in pairs if a != b)
However, this version (like your original) will create a copy of the input list with lst[1:], so that's not really just a single loop, either. To fix that, you could e.g. use itertools.tee or islice.
You can try to check if sorted ascending way, if not: array[::-1], and check again.
array[::-1] reverses the array.

Counting change dynamic programming: Does order of coin matter?

This is the typical count change problem. I tried translating into a tabulation solution a couple of times, until I found one particular translation by another person strange.
def first_denomination(kinds):
x=[50,20,10,5,1]#erroneous for the given DP code
#x=[1,5,10,20,50] #works with DP
return x[kinds-1]
def cc(amt,kinds): #either order of x gets cc(100,5)= 343
if amt==0:
return 1
elif amt<0 or kinds==0:
return 0
else:
return cc(amt,kinds-1)+cc(amt-first_denomination(kinds),kinds)
def dp_cc (amount , kinds_of_coins ): #must put coins in ascending order to get 343
row = [1]*( kinds_of_coins )
table = []
for i in range ( amount +1):
table . append (list(row))
for j in range(kinds_of_coins):
table[0][j]=1
for i in range (1, amount +1):
for j in range (1, kinds_of_coins ):
d = first_denomination ( kinds_of_coins -j+1)
if i >=d:
table [i][j] = table [i][j-1] + table [i-d][j]
else :
table [i][j] = table [i][j-1]
return table [ amount ][ kinds_of_coins -1]
The problem here is if I arrange x in descending order of coins, I get dp_cc(100,5)=8061 which is strange, while only the ascending implementation gets dp_cc(100,5)=343. I have tried other implementations that works for both cases, but I'm not sure why this particular one doesn't work, since order shouldn't matter in these kind of questions. Can anyone enlighten me why?

Sorting from smallest to biggest

I would like to sort several points from smallest to biggest however.
I will wish to get this result:
Drogba 2 pts
Owen 4 pts
Henry 6 pts
However, my ranking seems to be reversed for now :-(
Henry 6 pts
Owen 4 pts
Drogba 2 pts
I think my problem is with my function Bubblesort ?
def Bubblesort(name, goal1, point):
swap = True
while swap:
swap = False
for i in range(len(name)-1):
if goal1[i+1] > goal1[i]:
goal1[i], goal1[i+1] = goal1[i+1], goal1[i]
name[i], name[i+1] = name[i+1], name[i]
point[i], point[i + 1] = point[i + 1], point[i]
swap = True
return name, goal1, point
def ranking(name, point):
for i in range(len(name)):
print(name[i], "\t" , point[i], " \t ")
name = ["Henry", "Owen", "Drogba"]
point = [0]*3
goal1 = [68, 52, 46]
gain = [6,4,2]
name, goal1, point = Bubblesort( name, goal1, point )
for i in range(len(name)):
point[i] += gain[i]
ranking (name, point)
In your code:
if goal1[i+1] > goal1[i]:
that checks if it is greater. You need to swap it if the next one is less, not greater.
Change that to:
if goal1[i+1] < goal1[i]:
A bunch of issues:
def Bubblesort - PEP8 says function names should be lowercase, ie def bubblesort
You are storing your data as a bunch of parallel lists; this makes it harder to work on and think about (and sort!). You should transpose your data so that instead of having a list of names, a list of points, a list of goals you have a list of players, each of whom has a name, points, goals.
def bubblesort(name, goal1, point): - should look like def bubblesort(items) because bubblesort does not need to know that it is getting names and goals and points and sorting on goals (specializing it that way keeps you from reusing the function later to sort other things). All it needs to know is that it is getting a list of items and that it can compare pairs of items using >, ie Item.__gt__ is defined.
Instead of using the default "native" sort order, Python sort functions usually let you pass an optional key function which allows you to tell it what to sort on - that is, sort on key(items[i]) > key(items[j]) instead of items[i] > items[j]. This is often more efficient and/or convenient than reshuffling your data to get the sort order you want.
for i in range(len(name)-1): - you are iterating more than needed. After each pass, the highest value in the remaining list gets pushed to the top (hence "bubble" sort, values rise to the top of the list like bubbles). You don't need to look at those top values again because you already know they are higher than any of the remaining values; after the nth pass, you can ignore the last n values.
actually, the situation is a bit better than that; you will often find runs of values which are already in sorted order. If you keep track of the highest index that actually got swapped, you don't need to go beyond that on your next pass.
So your sort function becomes
def bubblesort(items, *, key=None):
"""
Return items in sorted order
"""
# work on a copy of the list (don't destroy the original)
items = list(items)
# process key values - cache the result of key(item)
# so it doesn't have to be called repeatedly
keys = items if key is None else [key(item) for item in items]
# initialize the "last item to sort on the next pass" index
last_swap = len(items) - 1
# sort!
while last_swap:
ls = 0
for i in range(last_swap):
j = i + 1
if keys[i] > keys[j]:
# have to swap keys and items at the same time,
# because keys may be an alias for items
items[i], items[j], keys[i], keys[j] = items[j], items[i], keys[j], keys[i]
# made a swap - update the last_swap index
ls = i
last_swap = ls
return items
You may not be sure that this is actually correct, so let's test it:
from random import sample
def test_bubblesort(tries = 1000):
# example key function
key_fn = lambda item: (item[2], item[0], item[1])
for i in range(tries):
# create some sample data to sort
data = [sample("abcdefghijk", 3) for j in range(10)]
# no-key sort
assert bubblesort(data) == sorted(data), "Error: bubblesort({}) gives {}".format(data, bubblesort(data))
# keyed sort
assert bubblesort(data, key=key_fn) == sorted(data, key=key_fn), "Error: bubblesort({}, key) gives {}".format(data, bubblesort(data, key_fn))
test_bubblesort()
Now the rest of your code becomes
class Player:
def __init__(self, name, points, goals, gains):
self.name = name
self.points = points
self.goals = goals
self.gains = gains
players = [
Player("Henry", 0, 68, 6),
Player("Owen", 0, 52, 4),
Player("Drogba", 0, 46, 2)
]
# sort by goals
players = bubblesort(players, key = lambda player: player.goals)
# update points
for player in players:
player.points += player.gains
# show the result
for player in players:
print("{player.name:<10s} {player.points:>2d} pts".format(player=player))
which produces
Drogba 2 pts
Owen 4 pts
Henry 6 pts

Categories

Resources