acokikoy's notes

最近気になる=[NoCode, Shopify], I am..=[Python, ウクレレ, マニュアル車, CMS] LoveなWebディレクター

毎朝Codewars@2019.05.28(火): Unique In Order

毎朝ちびちびCodewars。

Unique In Order [6級] www.codewars.com

今日のお題:

""" unique_in_order(iterable)
  与えられた文字列から、隣同士同じ文字を取り除いて、
  残りを文字のリストで返す。ただし、文字の並び順は変えない。

 例:
 unique_in_order('AAAABBBCCDAABBB') == ['A', 'B', 'C', 'D', 'A', 'B']
 unique_in_order('ABBCcAD')         == ['A', 'B', 'C', 'c', 'A', 'D']
 unique_in_order([1,2,2,3,3])       == [1,2,3]


Args:  
    iterable (str):  
Returns:  
    連続する重複文字を取り除いた文字のリスト (list):  
"""

コード

me

https://www.codewars.com/kata/unique-in-order/solutions/pythonhttps://www.codewars.com/kata/reviews/54e659a9e323fec7c30002a7/groups/577c74e3ae280793f0001456

# [6 kyu] Unique In Order
# https://www.codewars.com/kata/unique-in-order/solutions/python

def unique_in_order(iterable):
    return [c for i, c in enumerate(iterable) if i == 0 or c != iterable[i-1]]

参考になった他ユーザの解法。

from itertools import groupby

def unique_in_order(iterable):
    return [k for (k, _) in groupby(iterable)]
  • groupby()という知らない関数が使われてた φ(・ェ・o)~メモメモ

文法、関数・メソッドnote

itertools.groupby(iterable, key=None)

itertools --- 効率的なループ実行のためのイテレータ生成関数 — Python 3.7.3 ドキュメント itertoolsモジュールは、
速くて旨い?!ビクトリノックスのアーミーナイフ的な関数が揃ってる模様。
以下、公式ドキュメントから丸コピ (消化し切れてない ^^;;

このモジュールは、高速でメモリ効率に優れ、単独でも組合せても使用することのできるツールを標準化したものです。同時に、このツール群は "イテレータの代数" を構成していて、pure Python で簡潔かつ効率的なツールを作れるようにしています。

例えば、SML の作表ツール tabulate(f) は f(0), f(1), ... のシーケンスを作成します。同じことを Python では map() と count() を組合せて map(f, count()) という形で実現できます。

これらのツールと組み込み関数は operator モジュール内の高速な関数とともに使うことで見事に動作します。例えば、乗算演算子を2つのベクトルにわたってマップすることで効率的な内積計算を実現できます: sum(map(operator.mul, vector1, vector2)) 。

groupby(iterable, key)関数は、

  • 同じキーを持つ要素からなる iterable 中のグループに対して、キーとグループを返すようなイテレータを作成する
  • keyが無指定な場合は、要素そのままがキーとして使われる
  • 本来はiterableをソートした状態で使う想定

およそ次と等価(via. 公式ドキュメント):

class groupby:
    # [k for k, g in groupby('AAAABBBCCDAABBB')] --> A B C D A B
    # [list(g) for k, g in groupby('AAAABBBCCD')] --> AAAA BBB CC D
    def __init__(self, iterable, key=None):
        if key is None:
            key = lambda x: x
        self.keyfunc = key
        self.it = iter(iterable)
        self.tgtkey = self.currkey = self.currvalue = object()
    def __iter__(self):
        return self
    def __next__(self):
        self.id = object()
        while self.currkey == self.tgtkey:
            self.currvalue = next(self.it)    # Exit on StopIteration
            self.currkey = self.keyfunc(self.currvalue)
        self.tgtkey = self.currkey
        return (self.currkey, self._grouper(self.tgtkey, self.id))
    def _grouper(self, tgtkey, id):
        while self.id is id and self.currkey == tgtkey:
            yield self.currvalue
            try:
                self.currvalue = next(self.it)
            except StopIteration:
                return
            self.currkey = self.keyfunc(self.currvalue)