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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Python

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

Q&A

解決済

2回答

402閲覧

python 文字 照合

aaa12

総合スコア18

Python

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

0グッド

0クリップ

投稿2017/10/25 10:51

編集2017/11/08 01:58

こんにちは。pythonでの数字列の照合方法についてお伺いしたく、質問させていただきます。

まず、こちらは以前教えていただいたコードです。

python

hoge_dict = {}

for line in f1:
hoge_dict[line.split(';')[0]] = line.rstrip()

for line in f2:
line = line.rstrip()
if line in hoge_dict:
f3.write(str(hoge_dict[line]) + '\n')
print(hoge_dict[line])

LouiS0616さんありがとうございます。
これは、f1に以下のような数字が入っており、
123456;7898553
145454;4538573
123456;4598295
:
:

f2に以下のような数字が入っています
134315
123456
:
そしてf1の;より左側と、f2の数字が一致したらf1の内容を出力し、f3
に書き込むというコードでした。

①今度はこれをf1の両側がf2に含まれている場合のみ、f1の内容を出力というものにしたいです。そのコードについて、自分で書いてみたのですが、見当違いだと思うので教えていただきたいです。

②f1の内容が
123457465786 134354365436 435435 341535 12344 1123456 343534
:
のように7つのデータになり、かつタブ区切りになった場合6番目の数字とf2が一致した場合新しいファイルに書き込む方法を教えていただきたいです。(f2のファイルには途中空行が混ざっている場合があるのでtry分で処理しています)
こちらは自分で以下のようなコードを書きましたが、エラーは出ずに実行されるのですがファイルに書き込まれていませんし、print分の内容も表示されません。わかる方、教えていただきたいです。

python

1hoge_dict = {} 2 3try: 4 for line in f1: 5 hoge_dict[line.split('\t')[5]] = line.rstrip() 6 7except: 8 pass 9 10else: 11 for line in f2: 12 line = line.rstrip() 13 if line in hoge_dict: 14 f3.write(str(hoge_dict[line]) + '\n') 15 print(hoge_dict[line]) 16

たぶ区切りの5番目と照合、これではなぜ駄目なのでしょうか?
理由もわからないです。
よろしくお願いします。

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

LouiS0616

2017/10/25 11:11

具体的にエラーとは何なのですか?
Lhankor_Mhy

2017/10/25 11:12

とりあえず、コードを天気ミスしてると思いますので、ご修正お願いします。
aaa12

2017/10/25 11:23

ご指摘ありがとうございます。
aaa12

2017/10/25 11:25

2は、エラーが出ずに実行されるのですがファイル3(f3)を開いてみると、書き込まれていません。エラー記載ミス申し訳ありません。よろしくお願いします。
aaa12

2017/10/25 11:26

転記ミス修正しました!
Lhankor_Mhy

2017/10/25 11:33

いや、たしかにそっちもなんですが……
aaa12

2017/10/25 11:35

すみません、どこのことをいってますか?
Lhankor_Mhy

2017/10/25 11:45

もちろん、2のコードのことです。
aaa12

2017/10/25 11:49

2のコードは1をかえただけで、これであってます!初心者なのでこれが変ということに気づけませんでした。1のコードを参考につくったので、一行かえただけでこのまま実行しています!
Lhankor_Mhy

2017/10/25 12:07

そのインデントは本当に正しいですか?
aaa12

2017/10/25 12:30

すみません。修正しました!
aaa12

2017/10/25 12:33

1つ目のコードをなおしました!2つ目はインデントこれで合ってると思うのですが、、、
Lhankor_Mhy

2017/10/25 12:35

それで1つ目ちゃんと動作します? むしろそっちが不思議なんですが…… もしかして、書いてないだけで、f2.close()をどこかに挟んでますか?
aaa12

2017/10/25 12:44

すみません。見るべきファイルを誤っていました!お手数掛けさせてしまい、申し訳ありませんでした、、、。これで、やり方を教えていただけるとありがたいです!!どうぞ、よろしくお願いします。
Lhankor_Mhy

2017/10/25 12:52

『エラーが出ずに実行されるのですがファイル3(f3)を開いてみると、書き込まれていません』とありますが、コンソールには出力されている、ということですか?
aaa12

2017/10/25 12:55

いえ、print文も出てきません。しかし、エラーも出てこないです。
Lhankor_Mhy

2017/10/25 12:58

当方で試したところ、問題なく出力されました。なので、ここに書いていない部分が原因だと思います。
aaa12

2017/10/25 13:05

もしかして、書き込みをaじゃなくてwにするところかもと、思ってやってみたらできました!!ありがとうございます!助かりました。また、①のコードの書き方もご存知でしょうか?こちらは見当もつかなくて、、、
aaa12

2017/10/25 13:30

すみません、2のファイルなのですがデータを増やすとエラーが出てきてしまいますFile "shogo.py", line 11, in <module> hoge_dict[line.split('\t')[5]] = line.rstrip() IndexError: list index out of range このようなエラーです。小さいデータだとできるのですが、、、なぜでしょうか?
Lhankor_Mhy

2017/10/26 00:58

再現しませんでしたが、f1に故意に空の行を入れると同じエラーになりました。EOF手前の改行などは見落としやすいかと思います。
aaa12

2017/10/26 05:03

故意にはいれてなくて、コマンドのcatを使って複数のファイルを1つにまとめているのですが、その際に無駄な空白が入ることはありますか?
Lhankor_Mhy

2017/10/26 05:59

エラーが出る行を特定したほうが早くないですか?
aaa12

2017/10/26 07:34

えっと、どういうことでしょうか?3行目のhoge_dictのとこでindexエラーがでます(+_+)
Lhankor_Mhy

2017/10/26 07:36

そういうことではなくて、f1のどの行を読んだ時にエラーが出ているのかを特定したほうが早いのでは、という意味です。
aaa12

2017/10/28 04:56

お返事が遅くなり申し訳ありません。f1には100万近くの大量のデータがあるのですが File "shogo.py", line 11, in <module> hoge_dict[line.split('\t')[5]] = line.rstrip() IndexError: list index out of rangeこのようなエラーです。この場合もファイル1の内容のズレを探せば良いのでしょうか?無知で申し訳ありません
aaa12

2017/10/28 05:15

ありがとうございます!
aaa12

2017/11/08 01:15

こんにちは、以前質問したものです。わからない箇所が出てきたのですが、もう一度お伺いしてよろしいですか?
guest

回答2

0

ベストアンサー

①今度はこれをf1の両側がf2に含まれている場合のみ、f1の内容を出力というものにしたいです。そのコードについて、自分で書いてみたのですが、見当違いだと思うので教えていただきたいです。

オリジナルのコードが見つかりませんが、
f1の両側がf2に含まれている場合、というのであれば、

python

1hoge_set = set([]) 2 3for line in f2: 4 key = line.rstrip() 5 hoge_set.add(key) 6 7for line in f1: 8 line = line.rstrip() 9 items = line.split(';') 10 if items[0] in hoge_set and items[1] in hoge_set: 11 f3.write(line + '\n') 12 print(line)

②f1の内容が
123457465786 134354365436 435435 341535 12344 1123456 343534
:
のように7つのデータになり、かつタブ区切りになった場合6番目の数字とf2が一致した場合新しいファイルに書き込む方法を教えていただきたいです。(f2のファイルには途中空行が混ざっている場合があるのでtry分で処理しています)
こちらは自分で以下のようなコードを書きましたが、エラーは出ずに実行されるのですがファイルに書き込まれていませんし、print分の内容も表示されません。わかる方、教えていただきたいです。

print文が実行されていないところを見るとtry-exceptにキャッチされたと考えるべきでしょう。

python

1try: 2 ... 3except Exception as e: 4 print(e) 5else: 6 ....

として、どんなエラーが出されたのかをデバッグすると良いと思います。
おそらく、f1の空行か.split('\t')が原因で[5]で配列外をアクセスしたせいだと想像しますが。
手元ではデータ等がないので再現できませんが、タブであれば、.split()だけでも区切りを処理できると思われます。
ところで、f2に空行があってもなくてももとのコードでは問題とはなりません。
一方で、もとのコードだとf1に空行があるとうまく動きません。
理由はf1に空行がある場合はtry文の場所が正しくないからです。

python

1hoge_dict = {} 2 3for line in f1: 4 try: 5 hoge_dict[line.split()[5]] = line.rstrip() 6 except Exception as e: 7 print(e, 'blank line skipping') 8 9for line in f2: 10 line = line.rstrip() 11 if line in hoge_dict: 12 f3.write(str(hoge_dict[line]) + '\n') 13 print(hoge_dict[line])

ちなみにこのhoge_dictを使った方法、keyとなる部分が一意的ではないとvalueは最後に出現したものに更新されていきます。
ゆえに、f1の6番目がf2に含まれているすべてのラインが求められている場合、出力が正しくありません。
このままだと、f1の6番目がf2に含まれているラインのうち最後のものが出力されます。

投稿2017/11/08 06:26

編集2017/11/08 06:29
mkgrei

総合スコア8560

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aaa12

2017/11/08 06:48

お返事ありがとうございます。 とても丁寧な文章で、①については理解することができました! ②の実行をしたところこのようなエラーが出ました。(IndexError('list index out of range',), 'blank line skipping') 私の理解不足でこのコードの実行できない理由がまだわかっていないのですが、f1に空白があるため実行できないということでしょうか?
mkgrei

2017/11/08 06:57

f1に空白文があるとline.split()の返り値が[]となるはずです。(print(line.split())をしてみればわかります。) このリストには中身がありませんので、6番目の要素は存在せず、line.split()[5]はリストの外側をアクセスしようとしてIndexErrorを出します。 そして、それをexcept文で受け取って念のために空行があることを出力しているだけで、コード自体は問題なく実行されているはずです。 最後にprint('Done')と追記すれば、実行終了後にDoneと表示されて、実際に最後まで実行しきったと安心できます。
aaa12

2017/11/08 07:00

丁寧にありがとうございます!おっしゃている意味がわかりました。tryでf1に空行ができてもそれを知らせるだけでそこは飛ばして実行するということですよね?ありがとうございます。 このエラーは無視して実行が終わるのを待てば良いという解釈であっていますか?
mkgrei

2017/11/08 07:04

それで正しいです。 もとのコードでも同様のエラーを出していますが、printして出力しているのではなく、passで潰しているだけです。 エラーと出力されて気持ち悪いのであれば、print文をpassで置き換えると出力はスッキリします。
aaa12

2017/11/08 07:06

ありがとうございます!それで実行してみます。データが莫大なため実行に時間がかかってしまいますが、正しくできたらまたお伝えいたします。ありがとうございます。
aaa12

2017/11/08 07:57

無事に実行できました、ありがとうございます!
mkgrei

2017/11/08 09:05

うまくいってよかったです。
aaa12

2017/11/08 12:39

度々申し訳ありません。実行は出来たのですが、このままだと重複したものが一つにまとめられて出力してしまっている気がします。 例えば、 f1が 123457465786 134354365436 435435 341535 12344 1123456 343534 156457465786 134354365436 635435 341535 12044 1123456 343534 と6番目のデータが同じ時、それが一つとしてカウントされている可能性はありますか?わかりにくくて申し訳ありません、、、伝わりましたでしょうか?
mkgrei

2017/11/08 13:26

最後にも書きましたが、keyとなる部分(これがf1の6番目に相当します)が一意的ではない(重複するものがあると)とvalueは最後に出現したものに更新されていきます。 ですので、f1の6番目の数字が一度でもf2に登場するものに対して、そのf1の行を書き出したい場合、f1に対して辞書を作るのではなく、f2に対して作るべきです。 それを行っているコードは①のものになります。 また速度が気になるのであれば、 hoge_dict = set([k.rstrip() for k in f2]) #f2の重複しない数を抽出 f1 = filter(None, [l.rstrip() for l in f1]) #f1の空行を削除 txts = [l for l in f1 if l.split()[5] in hoge_dict] #条件(f1の6番目がf2に出現)に合う行の抽出 f3.write('\n'.join(txts)) #書き出し のようにリスト内包表記で書くと早くなります。 おまけ: 残るボトルネックはif l.split()[5] in hoge_dictにあって、hoge_dictが非常に大きい場合マッチングに時間がかかります。 これは常套手段として、予め並び替えなどをすることによって、2分探索することで早くする余地があります。
aaa12

2017/11/08 13:33

お返事ありがとうございます!最後のアドバイスはそういう意味だったのですね、勘違いしていました。ありがとうございます。 コード1にこのコード2のtry分を入れる場合どのようにすれば良いのでしょうか?無知で申し訳ありません。また;区切りがタブ区切りになるのはitems = line.split(';')を書き換えれば良いでしょうか?また、他に書き換える部分はありますでしょうか? あらかじめ並べ替えとは、ソートコマンドで行ってからということですか?それなら自分にもできそうです!
mkgrei

2017/11/08 13:46 編集

コード1:遅い版(インデントが壊れますね…) hoge_set = set([]) for line in f2: key = line.rstrip() hoge_set.add(key) for line in f1: line = line.rstrip() items = line.split() #';'削除 if items[5] in hoge_set: #0->5, and以降削除 f3.write(line + '\n') print(line) 主な遅い理由:for文を使っていること。print文を使っていること。 try文が必要なくなるように空行削除を先にやっているので、以下のコードをそのまま実行すればよいです。 コード2:早い版(インデントはこれで正しいです) hoge_dict = set([k.rstrip() for k in f2]) #f2の重複しない数を抽出 f1 = filter(None, [l.rstrip() for l in f1]) #f1の空行を削除 txts = [l for l in f1 if l.split()[5] in hoge_dict] #条件(f1の6番目がf2に出現)に合う行の抽出 f3.write('\n'.join(txts)) #書き出し
aaa12

2017/11/08 13:58

ありがとうございます。for文を書かないと早くなるのですね!最初に空行を削除すれば for文を使わずに済むということは思いつきませんでした、他のコードにも応用させていきたいと思います、ありがとうございます! これも実行に時間がかかるので完了したらまたご連絡させていただきます。
aaa12

2017/11/08 14:03

txts = [l for l in f1 if l.split()[5] in hoge_dict] の行でindex error が出てしまったのですが、どこが原因でしょうか?
mkgrei

2017/11/08 14:09

空行だけではなく、数字が6個未満の行があるということだと思います。 f1 = filter(None, [l.rstrip() for l in f1]) を f1 = [l for l in f1 if len(l.rstrip().split())>=6] に変えると動くはずです。 しかしどのような理由でその行に7個数字がないのかが不明ですが。 行ずれがどこかで起きているかもしれません。
aaa12

2017/11/08 14:19

ありがとうございます、これでまた実行してみます!
guest

0

そのインデントで本当に実行しているなら、おそらくそれが原因です。
その書き方だと2重ループになりますので、f1の1行目を処理した時点でf2はEOFまで進んでいるはずです。closeしない限りは、2周目以降は内側のループが実行されないと思います。

投稿2017/10/25 12:40

Lhankor_Mhy

総合スコア35865

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

aaa12

2017/10/25 12:56

こちらの回答に目を通していなかったです。ありがとうございます!
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問