質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.86%

  • Python

    5870questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Pythonのsumよるテキストファイルの行数カウント方法の仕組みについて

解決済

回答 2

投稿

  • 評価
  • クリップ 0
  • VIEW 1,030

Bicepper

score 3

前提

sumによるテキストファイルの行数カウント方法の仕組みが知りたい

お世話になります。
テキストファイルの行数をカウントしようと思い、当初は以下の方法で実装していました。

実装ソースコード

f = open('text.txt', 'r')
string = f.readlines()
print(len(string))

ところが、調べているうちに、以下の方法でもカウント可能なことがわかりました。

第三者のソースコード

print(sum(1 for i in open('hightemp.txt', 'r')))


参考:How to get line count cheaply in Python?

疑問・試したこと

率直に申しまして、このsumによるカウント方法の仕組みが知りたいです。
なぜこれでカウントできるのでしょうか。
簡単な検証方法として以下を試しました。

test = ['a', 'b', 'c', 'd', 'e']

print(sum(1 for i in test))
# 結果:5
print(sum(2 for i in test))
# 結果:10
print(sum(3 for i in test))
# 結果:15

個人的に導き出した結論

「ジェネレータ式で生成されたジェネレータオブジェクトの総数にforの前に書かれている数を掛け合わせた結果が出力」
上記の理解で正しいのでしょうか。
Python初学者のためsumの動き、ジェネレータ式の動きをしっかりと把握していない部分もあるかと思います。
至らぬところがあると思いますが、誤解、間違い等の箇所があれば是非ご指摘いただきたいです。
よろしくお願いいたします。

参考:組み込み関数:sum

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

回答 2

+2

a = [1 for i in range(5)]
#[1,1,1,1,1]
sum(a)
#1+1+1+1+1=5


sumするとジェネレータがStopまで実行されて、要素の数だけ1を足し合わせていることになります。


サイズがよほど大きくないとプロセスを立てるほうが時間を食うので、なんとも言えませんが、

import subprocess
run = subprocess.getoutput
t = run('wc -l {0}'.format(filename))
print(t)
l = int(t.split()[0])
print(l)

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/05 17:10

    回答ありがとうございます。
    「forの前の数が要素数分足されていく」ということなのですね。
    理解が間違っていました。ありがとうございました。

    キャンセル

  • 2018/01/05 17:24

    5.4G/977674行のファイルについて行数を数えてみたところ、
    sumを使った方法だと~3.47s
    wcを使った方法だと~0.52s
    になりました。
    ファイルが大変大きい場合はPythonで頑張らないほうがよいのかもしれません。

    キャンセル

  • 2018/01/05 17:55

    コメントありがとうございます。
    すみません、まだそこまで発想を展開させることができなかったのですが、読み込むファイルサイズのことも考慮すると、subprocessでwcを使用した方が無難、ということでしょうか。
    大変勉強になります。検証もしていただきありがとうございました!

    キャンセル

  • 2018/01/06 08:23

    「だいたいこのぐらいという数がわかればいい」か「後続のPythonの処理のために必要な値」なのか気になりました。前者ならいいですけど、Pythonでイテレートする回数とwcの結果は違うものであって、数が違うことはありえますので。

    キャンセル

  • 2018/01/06 11:09

    quiquiさん、コメントをありがとうございます。

    wcは\nの数を数えるので、Pythonのイテレート回数より1だけずれるケースがありますね。

    キャンセル

  • 2018/01/06 12:27

    quiqui様、mkgrei様
    コメントありがとうございます。
    もともとこの疑問に至った経緯が、以下のサイトの「10.行数のカウント」問題を解いていたためでした。
    http://www.cl.ecei.tohoku.ac.jp/nlp100/#sec10
    後続があるわけではないですが、「行数をカウントせよ」と明確な数を求めていますので、どちらかというと後者になります。

    キャンセル

checkベストアンサー

+1

ちょっと奇をてらった書き方に見えます。
理解のために、適当にsumを模した関数を作ってみましょう。

def my_sum(it):
    total = 0
    for elem in it:
        total += elem
    return total

my_sum([0, 1, 2, 3, 4])

つまり、問題のコードは、次のように書いているのと結果的には同じです。

total = 0
for _ in open(hoge, 'r'):
    total += 1
print(total)

これならわかりますかね。

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2018/01/05 17:11

    回答ありがとうございます。
    sumの動きについてよく理解できました。
    ありがとうございました。

    キャンセル

  • 2018/01/05 17:27 編集

    元のリンクがとても大きなファイルを一気に読みこまずに行数を数える方法についてだったので、一応モチベーションはわかります。
    内包表記のように書くことによってどれほど加速できるのかは測定してみないとわかりませんが。

    追記:内包表記によって全く早くなりませんでした。素直にfor文で足すのと同じですね。

    キャンセル

  • 2018/01/05 17:38

    Pythonなら行数くらいちょいちょい取得できるかと思いましたが、案外モロな関数はないみたいですね。
    mkgreiさんの回答のようにするのが現実的そうです。

    キャンセル

  • 2018/01/05 17:57

    mkgrei様、LouiS0616様
    コメントありがとうございます。
    大変勉強になりました。

    キャンセル

  • 2018/01/06 08:28

    変更可能なオブジェクトも再代入可能な変数も持たない言語なら「当然の様にこう書く」という典型な書き方だと思いますよ。 http://bigonotation.altervista.org/en/2017/04/24/how-to-find-length-list-haskell/

    キャンセル

  • 2018/01/06 15:05

    他言語に影響された書き方、ということでしょうか。
    Haskellは全く書いたことがないですので、非常に新鮮な感じです。

    実行速度がほぼ同じとなると、メモリを食わない分sumを用いた方法の方が有益なのかもしれませんね。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.86%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

関連した質問

同じタグがついた質問を見る

  • Python

    5870questions

    Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。