4

getitemiterメソッド、またはジェネレーター関数を実装して、作成したクラスとクラスコンテナーをソートする方法について、実際にいくつかの助けを借りることができました。

send_time (datetime) および period_length (int) 属性を持つ Report クラスを作成しました。また、collections.deque から継承する ReportDeque コンテナも作成しました。

クラスとそのコンテナーの両方に並べ替え機能を追加する必要があります。

これまでのところ、ソートは正常に機能していますが、 list.sort() スタイルを機能させたいと考えています。

  sortedList = sorted(list, key=lambda report: report.send_time)
  sortedDeque = sorted(deque, key=lambda report: report.send_time)

Report にgetitemを実装し、ReportDeque にiter、 next メソッドを実装するのに苦労しています。これをすべて機能させるために必要な例が見つからないようです。

collections.deque コンテナーをソートするには、ジェネレーター関数を使用する必要があるかもしれません。さまざまな方法で deque をソートするためのさまざまなジェネレーターがあると便利です。

以下は私のテストケースです。以下のコードで単体テストを実行するには、次のように入力します。

  python -m unittest test_reports

出力はこの投稿の最後にあります。

前もって感謝します...

------------------- test_reports.py 省略 --------------------------

#!/usr/bin/env python

from datetime import datetime
from collections import deque
import unittest
import inspect

class Report(object):
    """
    Contains all information contained in a report
    """
    def __init__(self, periodStart, periodEnd, sendTime):
        self.period_start = periodStart
        self.period_end = periodEnd
        self.send_time = sendTime
        self.send_timestamp = (sendTime - datetime(1970, 1, 1)).total_seconds()
        self.period_length = (periodEnd - periodStart).total_seconds()

    #def __getitem__(self, key):

class ReportDeque(deque):
    """
    Container for processing, sorting Report objects
    """

    #def __iter__(self)

    #def next(self)

class TestReports(unittest.TestCase):

    def setUp(self):

        self.list = []
        self.deque = ReportDeque()

        # send_time 12/4/13, day length report
        report = Report(datetime(2013, 12, 3, 0), datetime(2013, 12, 3, 23), datetime(2013, 12, 4, 0))
        self.list.append(report)
        self.deque.append(report)
        # send_time 12/3/13, day length report
        report = Report(datetime(2013, 12, 2, 0), datetime(2013, 12, 2, 23), datetime(2013, 12, 3, 0))
        self.list.append(report)
        self.deque.append(report)
        # send_time 12/2/13, day length report
        report = Report(datetime(2013, 12, 1, 0), datetime(2013, 12, 1, 23), datetime(2013, 12, 2, 0))
        self.list.append(report)
        self.deque.append(report)

        # sorted with key function works
        self.sortedList = sorted(self.list, key=lambda report: report.send_time)
        self.sortedDeque = sorted(self.deque, key=lambda report: report.send_time)

    def test_sort_deque_send_time(self):
        self.print_inspect()
        # deque does not have sort method. How to sort it?
        self.deque.sort()
        firstReport = self.deque[0]
        print "send_time {} period_length {}".format(firstReport.send_time, firstReport.period_length)
        self.assertEqual(firstReport.send_time, datetime(2013, 12, 2, 0, 0, 0, 0))

    def test_sort_list_send_time(self):
        self.print_inspect()
        # list.sort() not working. How to implement __get_item___?
        self.list.sort()
        firstReport = self.list[0]
        print "send_time {} period_length {}".format(firstReport.send_time, firstReport.period_length)
        self.assertEqual(firstReport.send_time, datetime(2013, 12, 2, 0, 0, 0, 0))

    def test_sorted_deque_send_time(self):
        self.print_inspect()
        firstReport = self.sortedDeque[0]
        print "send_time {} period_length {}".format(firstReport.send_time, firstReport.period_length)
        self.assertEqual(firstReport.send_time, datetime(2013, 12, 2, 0, 0, 0, 0))

    def test_sorted_list_send_time(self):
        self.print_inspect()
        firstReport = self.sortedList[0]
        print "send_time {} period_length {}".format(firstReport.send_time, firstReport.period_length)
        self.assertEqual(firstReport.send_time, datetime(2013, 12, 2, 0, 0, 0, 0))

    def print_inspect(self):
        calling_function = inspect.stack()[1][3]
        print "\nin {}()".format(calling_function)


if __name__ == "__main__":
    unittest.main()

------------------- test_reports.py 省略 --------------------------

    $ python -m unittest test_reports


    in test_sort_deque_send_time()
    E
    in test_sort_list_send_time()
    send_time 2013-12-04 00:00:00 period_length 82800.0
    F
    in test_sorted_deque_send_time()
    send_time 2013-12-02 00:00:00 period_length 82800.0
    .
    in test_sorted_list_send_time()
    send_time 2013-12-02 00:00:00 period_length 82800.0
    .
    ======================================================================
    ERROR: test_sort_deque_send_time (test_reports.TestReports)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "test_reports.py", line 51, in test_sort_deque_send_time
        self.deque.sort()
    AttributeError: 'ReportsDeque' object has no attribute 'sort'

    ======================================================================
    FAIL: test_sort_list_send_time (test_reports.TestReports)
    ----------------------------------------------------------------------
    Traceback (most recent call last):
      File "test_reports.py", line 62, in test_sort_list_send_time
        self.assertEqual(firstReport.send_time, datetime(2013, 12, 2, 0, 0, 0, 0))
    AssertionError: datetime.datetime(2013, 12, 4, 0, 0) != datetime.datetime(2013, 12, 2, 0, 0)

----------------------------------------------------------------------
Ran 4 tests in 0.011s

FAILED (failures=1, errors=1)
4

1 に答える 1

6

まず、明示的なキーなしで注文できるように、Report オブジェクトを比較可能にする必要があります。おそらく豊富な比較を読む必要が__cmp__ありますが、うまくいくでしょう。

class Report(object):
    """
    Contains all information contained in a report
    """
    def __init__(self, periodStart, periodEnd, sendTime):
        self.period_start = periodStart
        self.period_end = periodEnd
        self.send_time = sendTime
        self.send_timestamp = (sendTime - datetime(1970, 1, 1)).total_seconds()
        self.period_length = (periodEnd - periodStart).total_seconds()

    def __cmp__(self, other):
        return cmp(self.send_time, other.send_time)

テスト中にテストに合格するために必要なのはこれだけですlist.sort()sorted(list)とのテストsorted(deque)も機能するはずですが、落とし穴があります。あなたは__getitem__実装の助けを求めているので、ソートをインプレースで行っていると信じsorted()ており、デキューもインプレースでソートすると思います。それはそれがどのように機能するかではありません。sorted(iterable)イテラブルのアイテムを含む新しいソート済みリストを返します。

本当に両端キューを並べ替えたい場合は、メソッドに両端キューの並べ替えアルゴリズムを実装してその場で実行する必要があります。両端キューを並べ替えるのにdeque.sort()どのアルゴリズムがより効率的かはわかりません (私はそうではありません)。それを行うのが理にかなっている場合でも)、おそらく両端キューを再構築し、python の非常に効率的な並べ替えアルゴリズムを活用する方が簡単だと思います。

class ReportDeque(deque):
    """
    Container for processing, sorting Report objects
    """

    def sort(self, *args, **kwargs):        
        items = [self.pop() for x in xrange(len(self))]
        items.sort(*args, **kwargs)
        self.extend(items)

これで、すべてのテストに合格するはずです。

アップデート

period_lengthsend_time が等しいときにあいまいさを解消するために使用したい場合は、次__cmp__のように に追加するだけです。

    def __cmp__(self, other):
         cmp((self.send_time, self.period_length), 
             (other.send_time, other.period_length))
于 2013-11-05T21:22:37.823 に答える