[解決済み] 文字列の行を反復処理する
質問
次のような複数行の文字列が定義されています。
foo = """
this is
a multi-line string.
"""
この文字列は、私が書いているパーサーのテスト入力として使われます。パーサー関数は
file
-オブジェクトを入力として受け取り、それに対して反復処理を行います。また、この関数は
next()
メソッドを直接呼び出して行をスキップさせるので、入力として本当に必要なのは反復子ではなくイテレータです。
その文字列の個々の行をイテレートするイテレータが必要なのです。
file
-オブジェクトがテキストファイルの行を越えるように。もちろん、私はこのようにすることができます。
lineiterator = iter(foo.splitlines())
これを行うより直接的な方法はありますか?このシナリオでは、文字列は分割のために一度トラバースされ、その後パーサーによって再度トラバースされる必要があります。私のテストケースでは、文字列は非常に短いので、それは重要ではありません、私は単に好奇心で尋ねています。Pythonはそのようなもののために非常に多くの便利で効率的なビルトインを持っていますが、私はこの必要性に合ったものを見つけることができませんでした。
どのように解決するのですか?
以下の3つの可能性があります。
foo = """
this is
a multi-line string.
"""
def f1(foo=foo): return iter(foo.splitlines())
def f2(foo=foo):
retval = ''
for char in foo:
retval += char if not char == '\n' else ''
if char == '\n':
yield retval
retval = ''
if retval:
yield retval
def f3(foo=foo):
prevnl = -1
while True:
nextnl = foo.find('\n', prevnl + 1)
if nextnl < 0: break
yield foo[prevnl + 1:nextnl]
prevnl = nextnl
if __name__ == '__main__':
for f in f1, f2, f3:
print list(f())
これをメインスクリプトとして実行すると、3つの関数が等価であることが確認できます。とは
timeit
(そして
* 100
に対して
foo
を使用すると、より正確な測定のために実質的な文字列を得ることができます)。
$ python -mtimeit -s'import asp' 'list(asp.f3())'
1000 loops, best of 3: 370 usec per loop
$ python -mtimeit -s'import asp' 'list(asp.f2())'
1000 loops, best of 3: 1.36 msec per loop
$ python -mtimeit -s'import asp' 'list(asp.f1())'
10000 loops, best of 3: 61.5 usec per loop
を使う必要があることに注意してください。
list()
の呼び出しは、イテレータが単に構築されるだけでなく、トラバースされることを保証するために必要です。
を使った私の試みに比べ、6倍も速いのです。
find
の呼び出しによる私の試みよりも 6 倍速く、さらに低レベルのアプローチよりも 4 倍速いのです。
保持すべき教訓:測定は常に良いことである(ただし正確でなければならない)。
splitlines
のような文字列メソッドは非常に高速な方法で実装されています。非常に低レベルのプログラミングで文字列をまとめる(特に
+=
のループ) によって文字列を組み合わせることは、非常に遅くなります。
編集 : @Jacob の提案を追加し、他の提案と同じ結果になるように少し修正しました(行の末尾の空白は保持されます)、すなわち。
from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl != '':
yield nl.strip('\n')
else:
raise StopIteration
測定は与える。
$ python -mtimeit -s'import asp' 'list(asp.f4())'
1000 loops, best of 3: 406 usec per loop
には及ばないが
.find
ベースのアプローチよりも優れているわけではありませんが、それでも、小さな1つ違いバグ (私の
f3
のような +1 と -1 が現れるループは自動的に off-by-one 疑惑を引き起こすはずで、そのような微調整がなく、それを持つべき多くのループもそうです -- 私は他の関数でその出力を確認できたので私のコードも正しいと信じていますが)。
しかし、分割ベースのアプローチはまだルールです。
余談ですが、おそらく
f4
の方がいいかもしれません。
from cStringIO import StringIO
def f4(foo=foo):
stri = StringIO(foo)
while True:
nl = stri.readline()
if nl == '': break
yield nl.strip('\n')
といった具合に、少なくとも冗長さは軽減されます。 末尾の
\n
を除去する必要があるため、残念ながら
while
ループを
return iter(stri)
(この
iter
の部分は最近のバージョンのPythonでは冗長で、2.3か2.4以降だと思いますが、これも無害です)。 多分、試してみる価値があります。
return itertools.imap(lambda s: s.strip('\n'), stri)
またはそのバリエーション -- しかし、これはかなり理論的な練習になるので、ここでやめておきます。
strip
をベースとした、最もシンプルで高速なものについては、かなり理論的なエクササイズになるので、ここで止めておきます。
関連
-
風力制御におけるKS原理を深く理解するためのpythonアルゴリズム
-
[解決済み】インポートエラー。モジュール名 urllib2 がない
-
[解決済み] JavaScriptで文字列が部分文字列を含むかどうかを確認する方法は?
-
[解決済み] C#のStringとstringの違いは何ですか?
-
[解決済み] なぜパスワードにはStringではなくchar[]が好まれるのですか?
-
[解決済み] Pythonには文字列の'contains'サブストリングメソッドがありますか?
-
[解決済み] PandasでDataFrameの行を反復処理する方法
-
[解決済み] 文字列の単語を反復処理するにはどうすればよいですか?
-
[解決済み] なぜC++はPythonよりもstdinからの行の読み込みが遅いのですか?
-
[解決済み】JavaScriptで文字列の出現箇所をすべて置換する方法
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
PyQt5はユーザーログインGUIインターフェースとログイン後のジャンプを実装しています。
-
[解決済み] _tkinter.TclError: 表示名がなく、$DISPLAY環境変数もない。
-
[解決済み】Python regex AttributeError: 'NoneType' オブジェクトに 'group' 属性がない。
-
[解決済み】numpyの配列連結。"ValueError:すべての入力配列は同じ次元数でなければならない"
-
[解決済み】終了コード -1073741515 (0xC0000135)でプロセス終了)
-
[解決済み】Python Error: "ValueError: need more than 1 value to unpack" (バリューエラー:解凍に1つ以上の値が必要です
-
[解決済み】LogisticRegression: Pythonでsklearnを使用して、未知のラベルタイプ: '連続'を使用しています。
-
[解決済み】Python: SyntaxError: キーワードは式になり得ない
-
[解決済み】django インポートエラー - core.managementという名前のモジュールがない
-
[解決済み] Python の `string.split()` のジェネレータバージョンはありますか?