3

次のように、日付のリストをインデックスとして使用するリストを作成しました。

>>> import datedlist
>>> import datetime
>>> dates = [datetime.date(2012,1,x) for x in range(2,6)]
>>> values = range(4,8)
>>> dates
[datetime.date(2012, 1, 2), datetime.date(2012, 1, 3), datetime.date(2012, 1, 4), datetime.date(2012, 1, 5)]
>>> dl = datedlist.DatedList(values, dates)
>>> dl
[4, 5, 6, 7]
>>> dl[datetime.date(2012,1,3)]
5

これまでのところすべて順調ですが、次のようにスライシング (拡張スライシングではなく) も使用できるようにしたいと考えています (以下は機能しませ- これが私が望む結果です)。

>>> datedlist[datetime.date(2012,1,3):datetime.date(2012,1,4)]
[5, 6]

これが私の試みです(明らかに機能しません):

class DatedList(list):

    def __init__(self, values, dates):
        self.dates = dates
        list.__init__(self, values)

    def __getitem__(self, date):
        if isinstance(date, slice):
            start = self.dates.index(slice[0])
            end = self.dates.index(slice[1])
            return [list.__getitem__(self, index) for index in range(start, end)]
        elif isinstance( date, datetime.date ) :
            index = self.dates.index(date)
            return list.__getitem__(self, index)
        elif isinstance(date, int):
            if date < 0:
                date += len(self)
            if date >= len(self):
                raise IndexError, "index out of range {}".format(date)
            return list.__getitem__(self, date)
        else:
            raise TypeError, "Invalid argument type."

スライス [0] とスライス [1] は、私の意図を説明するためだけのものです。isinstance(date, int) はデバッグ用にのみ存在します。製品コードでは削除されます。

ここに質問があります: datetime.date オブジェクトをインデックスとして使用するスライスをどのように実装できますか?

編集(ニブラーの2番目のコメントの後):私もgetsliceを試しました(ドキュメントではgetsliceは廃止されたと書かれていますが)。クラスは次のようになります (構文のために isinstance-slice ビットがコメント化されています)。

class DatedList(list):

    def __init__(self, values, dates):
        self.dates = dates
        list.__init__(self, values)

    def __contains__(self, date):
        return date in self.dates

    def __getslice__(self, fromdate, todate):
        i_from = self.get_index(fromdate)
        i_to = self.get_index(todate)
        print i_from, i_to
        return [list.__getitem__(self, i) for i in range(i_from, i_to)]

    def __getitem__(self, date):
        if isinstance(date, slice):
            pass
#            start = self.dates.index(slice[0])
#            end = self.dates.index(slice[1])
#            return [list.__getitem__(self, i) for i in range(start, end)]
        elif isinstance(date, datetime.date):
            index = self.get_index(date)
            return list.__getitem__(self, index)
        elif isinstance(date, int):
            if date < 0:
                date += len(self)
            if date >= len(self):
                raise IndexError, "index out of range {}".format(date)
            return list.__getitem__(self, date)
        else:
            raise TypeError, "Invalid argument type."

    def get_index(self, date):
        if date in self.dates:
            index = self.dates.index(date)
        elif date < self.dates[0]:
            index = 0
        elif date > self.dates[-1]:
            index = len(self.dates) - 1
        return index

結果は次のとおりです。

>>> print dl[datetime.date(2012,1,3):datetime.date(2012,1,5)]
>>> None

印刷が実行されないため、明らかに getslice はまったく使用されません。スライスが要求されたときに getitem が実行されるようですが、スライスで datetime.date を使用できないようです。/編集

注: リストをサブクラス化することは明らかに良い考えではありませんが、これまでに試した代替手段のどれもうまく機能していないようです (またはまったく機能しませんでした)。

  • クラスをゼロから構築する: [] 表記を機能させることができませんでした:

    dl = DatedList(values, dates)
    value = dl[some_date]       # I want this to work
    value = dl.value(same_date) # I don't want this
    
  • 辞書の使用を検討しましたが、リストを並べ替える必要があり、スライスも使用する必要があります。

  • collections.Sequence のサブクラス化も試みましたが、結果は次のようになりました。

    TypeError: 記述子 ' init ' には 'list' オブジェクトが必要ですが、'DatedList' を受け取りました

4

2 に答える 2

4

これを再実装するのではなく、既存の timeseries 実装のいくつかを確認することをお勧めします。Pandasには、 scikits.timeseriesと同様に、かなり優れたものがあります。

例として、パンダの場合:

In [1]: from pandas import Series, DateRange

In [2]: import datetime

In [3]: ts = Series(range(12), index=DateRange('1/1/2000', periods=12, freq='T'))

In [4]: ts
Out[4]: 
2000-01-03     0
2000-01-04     1
2000-01-05     2
2000-01-06     3
2000-01-07     4
2000-01-10     5
2000-01-11     6
2000-01-12     7
2000-01-13     8
2000-01-14     9
2000-01-17    10
2000-01-18    11

In [5]: ts[datetime.datetime(2000,1,10):]
Out[5]: 
2000-01-10     5
2000-01-11     6
2000-01-12     7
2000-01-13     8
2000-01-14     9
2000-01-17    10
2000-01-18    11

または、そこでソース コードを調査し、特定のケースに合わせて再実装することもできます。

于 2012-05-21T01:11:49.863 に答える
3

これは非常に単純な例です。基本的には、パラメータを__getitem__マッピングに渡し、マッピングを介して渡すため、構築リストの動作を活用できます。

あなたが言ったように、__getslice__時代遅れです、__getitem__ただそれが渡されたことに気づきsliceそしてそれを適切に扱う必要があります。

import datetime
class DatedList(list):

    def __init__(self, values, dates):
        list.__init__(self, values)
        self.dates = dates
        self._dt_to_idx = {k:v for v,k in enumerate(dates)}

    def __getitem__(self, arg):
        if isinstance(arg, slice):
            start = self._dt_to_idx[arg.start]
            stop = self._dt_to_idx[arg.stop]
            return list.__getitem__(self, slice(start, stop, arg.step))
        else:
            return list.__getitem__(self, self._dt_to_idx[arg])    


dates = [datetime.date(2012,1,x) for x in range(2,6)]
dl = DatedList([1,2,3,4], dates)
print dl[dates[2]]
print dl[dates[1]:dates[3]]

より複雑なマッピングが必要な場合-スキップされた日付などを処理するために、マッピングを実行するメソッドを定義し、使用する場所でそれを呼び出すだけです。self._dt_to_idx[...]

于 2012-05-21T04:34:30.857 に答える