2012-04-24 12 views
3

私は並べ替える必要があるデータのリストを持っています。悲しいことに、これらのオブジェクトの命名規則はあまり一貫していません。データは、最も頻繁に実数である文字列のリストですが、最後に文字があることがあります。このリストの許容値のいくつかの例は以下のようなものです:実数と文字の混合リストの並べ替え

# this is how it should be sorted 
['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2'] 

これらはデータベース内にあるので、私の最初の考えは、ソートされた結果を返すために、次のDjangoの方法を使用していたが、次のようにそれを返します。

#took out unneeded code 
choices = [l.number for l in Locker.objects.extra(
       select={'asnumber': 'CAST(number as BYTEA)'}).order_by('asnumber')] 
print choices 
==> ['1', '1.1', '101.1', '101.2', '2', '2.1A', '2.1B', '2.2A'] 

悲しいことに、それを並べ替えることができませんでした。だから私の新しい計画は、python sortedメソッドで動作するメソッドを書くことですが、私はまだこれを書く方法についてはわかりません。私は文字列の実数部分をソートし、その後に2番目のソートとして、最後に付加された文字でソートする方法を見つける必要があります。

これについての相談はどこですか?

+0

数字、ドット、 'A'または' B'以上の文字だけですか? –

+1

あなたは正面を実数のように並べ替えたいと思っていますが、それが本当にバージョン番号の大部分であるかどうかを疑問に思うのは助かりません。 '1.3'を '1.12'の前後にソートしますか? – kgrittn

+0

ああ、あなたは正しい、私は実際の数よりも具体的にしなければなりません。これはマイナーバージョン番号に似ていますが、うまくいけば1.12は存在しませんが、もしあればそれが他のものの前に来るはずです。私は明日チェックインする必要があります。どの答えがうまくいくかを調べる – Bob

答えて

4

DBMSに並べ替えをさせてください。それはとてもうまくいきます。アプリケーションでパフォーマンスに匹敵することはほとんどありません。

あなたが得たすべては、単にあなたができる、AまたはBとの端数が追加された場合:あまりにも

SELECT * 
FROM (
    SELECT unnest(
    ARRAY['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2']) AS s 
    ) x 
ORDER BY rtrim(s, 'AB')::numeric, s; 

要求されたとおりに受注し、速いです、。 ARRAYunnest()の副選択は、簡単なテストケースを構築するためのものです。 ORDER BY句は重要です - rtrim() in the manual

他の文字が含まれている場合は、質問を更新して画像を完成させることができます。

+0

トリッキーなデータの場合、ソートキーを生成するPL/PgSQL関数を書くことができます。 –

0

私は途中で終了上の文字の任意の量に一般化:

from itertools import takewhile 

def sort_key(value): 
    cut_point = len(value) - len(list(takewhile(str.isalpha, reversed(value)))) 
    return (float(value[:cut_point]), value[cut_point:]) 

sorted((
    l.number 
    for l in Locker.objects.extra(select={'asnumber': 'CAST(number as BYTEA)'}) 
), key = sort_key) 
0

スプリットタプルに文字列 - 実数(float型または小数に変換)し、文字の多くの場合、空の文字列。タプルをソートし、Pythonの組み込みソート(timesort)を使用すると、本当に速くなるはずです。

科学的表記があなたの実例で許可されているかどうか、たとえば1e10に注意してください。

比較がさらに複雑になる可能性がある場合は、タプルの代わりにクラスを使用します。しかし、タプルはおそらくより高速になります。次に、1つ以上の比較関数を定義します(Python 2.xまたは3.xの場合に応じて)。

タプル等の要素0、要素1を、比較

あなたのクラスの代替がCMP法または3.xと同等を持っている必要があります。

1
x = ['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2'] 

#sort by the real number portion 

import string 

letters = tuple(string.ascii_letters) 

def change(x): 
    if x.endswith(letters): 
     return float(x[:len(x) -1]) 
    else: 
     return float(x) 

my_list = sorted(x, key = lambda k: change(k)) 

結果:

>>> my_list 
['1', '1.1', '1.2', '2', '2.1A', '2.1B', '2.2A', '101.1', '101.2'] 
0

文字列として文字列を保存し、それは間違ったアプローチのように思えるソートするために、それを解析します。あなたが本当に

  • メジャー番号がある持っているものであれば
  • マイナー番号
  • オプションの改正

その後、私は強く、二つの整数とテキストフィールドとして、それを保存することをお勧め。 major_number、minor_number、revisionの並べ替えは、まったく同じように動作します。データベースレベルでビューとしてasnumberを定義するか、または関連する__cmp__()を持つ3つの基数に基づくクラスとしてasnumberを定義することができます。

関連する問題