2016-08-08 14 views
0

Моя цель: Сортировка list товаров (dict) сначала по цене, а затем по названию. Моя проблема: Str значения с номерами в них не отсортированы должным образом (AKA «сортировка человека» или «естественная сортировка»).Python сортировка str цена с двумя десятичными знаками

Я нашел эту функцию с подобным вопросом: Python sorting list of dictionaries by multiple keys

def multikeysort(items, columns): 
    from operator import itemgetter 
    comparers = [((itemgetter(col[1:].strip()), -1) if col.startswith('-') else 
        (itemgetter(col.strip()), 1)) for col in columns] 
    def comparer(left, right): 
     for fn, mult in comparers: 
      result = cmp(fn(left), fn(right)) 
      if result: 
       return mult * result 
     else: 
      return 0 
    return sorted(items, cmp=comparer) 

Проблема в том, что мои Цены str типа, например:

products = [ 
    {'name': 'Product 200', 'price': '3000.00'}, 
    {'name': 'Product 4', 'price': '100.10'}, 
    {'name': 'Product 15', 'price': '20.00'}, 
    {'name': 'Product 1', 'price': '5.05'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

Так они получают отсортированы по алфавиту, например:

'100.10' 
'20.10' 
'3000.00' 
'4.99' 
'5.05' 

Simi бенно, когда я сортировать по имени, я получаю это:

'Product 1' 
'Product 15' 
'Product 2' 
'Product 200' 
'Product 4' 

Имена должны быть перечислены в «человеческом» порядке (1,2,15 вместо 1,15,2). Можно ли это исправить? Я довольно новичок в python, так что, возможно, мне не хватает чего-то жизненно важного. Благодарю.

EDIT

Дополнительная информация: Я посылаю список продуктов шаблона Джанго, который требует номера, чтобы быть правильно отформатирована. Если я буду плавать по ценам, а затем их не плавать, я должен дважды перебирать список продуктов, что кажется излишним.

+1

Ваши цены должны быть строками? Лучше всего было бы отбросить их на floats – Tyler

+0

'int' type удаляет десятичные разряды ('1.00' = '1'), а' float' удаляет одно десятичное число ('1.00' = '1.0'), т хорошо выглядеть в корзине! – ThePloki

ответ

2

Я думаю, что вам лучше всего, чтобы проанализировать цены как поплавки (так что вы можете отсортировать их):

float("1.00") 
# output: 1.0 

затем вывести их с двумя знаками после запятой:

"{:.2f}".format(1.0) 
# output: "1.00" 
+0

Если я делаю это так, мне нужно выполнить итерацию всех результатов после сортировки их только для правильного ее форматирования. Я просмотрю свой код и посмотрю, могу ли я минимизировать итерацию. Благодарю. – ThePloki

1

Try типажей их плавает в вопросе, и когда вам нужно распечатать 2 десятичных знака, вы можете легко форматировать выход так:

float_num = float("110.10") 
print "{0:.2f}".format(float_num) # prints 110.10 
3

Ваша функция сортировки является излишним. Попробуйте этот простой подход:

from pprint import pprint 

products = [ 
    {'name': 'Product 200', 'price': '3000.00'}, 
    {'name': 'Product 4', 'price': '100.10'}, 
    {'name': 'Product 15', 'price': '20.00'}, 
    {'name': 'Product 1', 'price': '5.05'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

sorted_products = sorted(products, key=lambda x: (float(x['price']), x['name'])) 
pprint(sorted_products) 

Результат:

[{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '5.05'}, 
{'name': 'Product 15', 'price': '20.00'}, 
{'name': 'Product 4', 'price': '100.10'}, 
{'name': 'Product 200', 'price': '3000.00'}] 

Суть моего решения, чтобы иметь функцию key возвращает кортеж из условий сортировки. Кортежи всегда сравниваются лексикографически, поэтому первый элемент - первичный, второй - вторичный, и т. Д.

+0

Мне это нравится! Единственная проблема заключается в том, что функция сортировки, которую я разместил, позволяет использовать неограниченное количество столбцов сортировки и отрицательную сортировку. Легко ли разрешить эти две вещи, используя ваш метод? – ThePloki

+1

Кроме того, это не устраняет вторую проблему сортировки по имени. – ThePloki

+0

Да, 'sorted()' поддерживает произвольное количество столбцов и отрицательную сортировку. –

0

Чтобы разорвать связи должны ли быть сортировка строк с использованием целочисленного значения от продукта, вы можете вернуть кортеж:

products = [ 
    {'name': 'Product 200', 'price': '2.99'}, 
    {'name': 'Product 4', 'price': '4.99'}, 
    {'name': 'Product 15', 'price': '4.99'}, 
    {'name': 'Product 1', 'price': '9.99'}, 
    {'name': 'Product 2', 'price': '4.99'}, 
] 

def key(x): 
    p, i = x["name"].rsplit(None, 1) 
    return float(x["price"]), p, int(i) 

sorted_products = sorted(products, key=key) 

Который даст вам:

[{'name': 'Product 200', 'price': '2.99'}, 
{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 4', 'price': '4.99'}, 
{'name': 'Product 15', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '9.99'}] 

В отличие от :

[{'name': 'Product 200', 'price': '2.99'}, 
{'name': 'Product 15', 'price': '4.99'}, 
{'name': 'Product 2', 'price': '4.99'}, 
{'name': 'Product 4', 'price': '4.99'}, 
{'name': 'Product 1', 'price': '9.99'}] 

используя только float(x['price']), x['name']

 Смежные вопросы

  • Нет связанных вопросов^_^