日付比較を簡略化する

私はリストソート関数(例えば、 date_list.sort(cmp = dcmp)の日付比較を行う以下のPythonコードを持っています。それをオンライナーにする。

def dcmp(a, b):
    amm, add, ayy = [int(v) for v in a.split('/')]
    bmm, bdd, byy = [int(v) for v in b.split('/')]
    v = cmp(ayy, byy)
    if v != 0: return v
    v = cmp(amm, bmm)
    if v != 0: return v
    return cmp(add, bdd)

更新:私が興味をそそられていることを明確にしましょう。関数からこのコードブロックを削除できますか?

    v = cmp(ayy, byy)
    if v != 0: return v
    v = cmp(amm, bmm)
    if v != 0: return v
    return cmp(add, bdd)
1
彼らはファイルから読み込まれ、'10/12/2011 'のように見えるので、dictキーとして使用されます。
追加された 著者 koblas,
なぜ引数の文字列が始まるのですか? Pythonには date タイプがあります。
追加された 著者 NullUserException,
date オブジェクトもキーとして使用できます。
追加された 著者 NullUserException,
私はまだNullUserExceptionがあると思います。 strptime を使用すると、これらの文字列をdatetimeオブジェクトに簡単に変換できます。これにより、比較を行うことができ、それでもdictキーとして使用できます。
追加された 著者 aganders3,

5 答え

cmp の代わりに key を使用できます。 キー関数を書く方がはるかに簡単で、1行で行うことができます。

date_list.sort(key = lambda s: datetime.strptime(s, '%m/%d/%Y'))

このインポートが必要になります:

from datetime import datetime
2
追加された
key を使用する方がより効率的です。
追加された 著者 PaulMcG,

日付変換を忘れて、これを文字列として行うことができます。それらを正しい順序に並べ替えるだけです。

amm, add, ayy = a.split('/')
bmm, bdd, byy = b.split('/')
return cmp(ayy+amm+add, byy+bmm+bdd)

ISO日付形式を使い、比較のために物事を適切な順序で並べ替えることを好む: YYYY-MM-DD 。また、海の向こうに誤解されないという利点もあります。

1
追加された
@ジョンマーチン、公正な批判。私が言ったように、私は先行ゼロが保証されている形式を使用することを好む。とdownvoteを説明してくれてありがとう、私は匿名の種類よりもはるかに良いことに感謝します。
追加された 著者 Mark Ransom,
-1 OPのコードとは異なり、日や月に先行ゼロがない場合は FAIL になります。
追加された 著者 John Machin,
海の向こう側には本当です。古典的な失敗:バッチジョブは、新しい「相手側」子会社によって提供されたファイルの出生日と雇用開始日の約60%を拒否します。労力をかけて「訂正」して再入力することを拒否します。もう37%の人が詰まっていても検出されないという認識は(まあまあのところまで)実現しません。
追加された 著者 John Machin,

私が探していたのは、このコードだけを置き換えることでした(日付は無視されます

v = cmp(ayy, byy)
if v != 0: return v
v = cmp(amm, bmm)
if v != 0: return v
return cmp(add, bdd)

正解は次のとおりです。

return cmp(ayy, byy) or cmp(amm, bmm) or cmp(add, bdd)

これは、次のように書くこともできます:

return cmp((ayy,amm,add), (byy,bmm,bdd))
0
追加された

あなたの月と日のすべてがゼロ詰めであり、あなたの日付が "01/01/2001"のようなm/d/Yフォーマットであれば、次のように書くことができます:

def datekey(d):
    m, d, y = d.split('/')
    return (y, m, d)

datelist.sort(key=datekey)

数値が常にゼロで埋められない場合は、比較のために各数値をintにキャストできます。

def datekey(d):
    m, d, y = d.split('/')
    return (int(y), int(m), int(d))

datelist.sort(key=datekey)

すべての日付が単純な形式である場合は、 strptime を使用するよりも、これは way

>>> import timeit
>>> print timeit.Timer("datelist.sort(key=datekey)",
...     setup="""\
... datelist = ['01/01/2001', '01/02/2001', '12/31/1999']
... def datekey(d):
...     m, d, y = d.split('/')
...     return (y, m, d)
... """).timeit()
3.3154168129

>>> print timeit.Timer("datelist.sort(key=datekey)",
...     setup="""\
... datelist = ['01/01/2001', '01/02/2001', '12/31/1999']
... def datekey(d):
...     m, d, y = d.split('/')
...     return (int(y), int(m), int(d))
... """).timeit()
11.1701700687

>>> print timeit.Timer("datelist.sort(key = lambda s: datetime.datetime.strptime(s, '%m/%d/%Y'))",
...     setup="""\
... datelist = ['01/01/2001', '01/02/2001', '12/31/1999']
... import datetime
... """).timeit()
59.2817358971

strptime is hugely powerful, very important to know, and very slow in this use case.

0
追加された
-1不正なコードのベンチマークは無駄です。 [1999、31、12] FAIL を生成する datekey('12/31/1999 '
追加された 著者 John Machin,
Aww、crud。編集されました。しかし、FAILについてのジャークではありません。
追加された 著者 Kirk Strauser,

これらの値を実際の日付に変換するのは確かにクリーンです(速度はそれほど重要である場合はベンチマークする必要があります)。

def dcmp(a, b):
    from datetime.datetime import strptime
    return strptime(a,'%m/%d/%Y') > strptime(b,'%m/%d/%Y')
0
追加された