アプリ版:「スタンプのみでお礼する」機能のリリースについて

教科書の問題で、リストの中に含まれるカテゴリーの数を数えるコードを書いています。
下記は正しく動作するコードになります。

def histogram(data):
 result=[]
 for i in range (len(data)):
  put_item(result,data[i])
  return result

def put_item(res,item):
 for i in range (len(res)):
  if res[i][0] == item:
   res[i][1] = res[i][1]+1
   return
 res.append([item,1])

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
histogram(data)

結果→
[['cat', 5], ['dog', 2], ['car', 2], ['cow', 1]]

練習のため、他の書き方も試しているのですが、下記のコードではうまく動作しません。

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
result=[]
for i in range (len(data)):
 for p in range (len(result)):
  if result[p][0] == data[i]:
   result[p][1] = result[p][1]+1
   break
 result.append([data[i],1])
print(result)

結果→
[['cat', 5], ['dog', 1], ['cat', 1], ['cat', 1], ['car', 1], ['dog', 1], ['car', 1], ['cat', 1], ['cow', 1], ['cat', 1]]

breakでリストの追加を止めているつもりなのですが、正しく動作しないのはなぜでしょうか。
宜しくお願い致します。

A 回答 (6件)

result.append([data[i],1])は break にかかわらず走るから


当たり前だよね。

それと、なにがなんでも配列で、検索は力任せのリニアサーチ
というのは 全然 pythonらしくない(^^;

辞書型の検索機能を使うとこんな感じです。

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
result = {}
for d in data:
 result[d] = result.setdefault(d, 0) + 1
print(result)

setdefault メソッドは辞書にキーが存在するかチェックし、
なければキー値ペアを辞書内に作成してその値を返すメソッドです。

collections.defaultdict(キー参照時、キーが無い場合自動的にキー値ペアを作成する辞書) を
使えばさらに読みやすいコードになります。

import collections

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
result = collections.defaultdict(lambda: 0)
for d in data:
 result[d] = result[d] + 1
print(result)
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。返信遅れてすみません。
とてもエレガントなコード教えて頂きありがとうございます。
Pythonらしいコードというものが何となくイメージできました。
練習のためアナログなやり方でコードを書く練習をしているのですが、Pythonの機能を使ってよりシンプルなコードを書けるようになりたいので、とても勉強になりました。これからも是非教えて下さい。

お礼日時:2020/02/27 01:20

>下記は正しく動作するコードになります。


ほんとですか?

 for i in range (len(data)):
  put_item(result,data[i])
  return result

これって、for の意味ない気がしますけど・・・
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。返信遅れてすみません。
ご質問の意図が分かっていないかもしれませんが、コード自体は正しく動作することは確認済です。

お礼日時:2020/02/27 01:14

breakは一番内側のループしか抜けません。

なので
 result.append([data[i],1])
の部分は内側のループをbreakで抜けても実行されてしまいます。
関数で書いている方はループの中でreturnしているのでループの後のappendもスキップされていますね。
Pythonの場合はループにもelse節を使えて、これはbreakした場合は実行されないので下記のようにappendを内側ループのelse節で実行すれば所望の動作になります。

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
result=[]
for i in range (len(data)):
 for p in range (len(result)):
  if result[p][0] == data[i]:
   result[p][1] = result[p][1]+1
   break
 else:
  result.append([data[i],1])

print(result)
    • good
    • 1
この回答へのお礼

いつもありがとうございます。返信遅れてすみません。
このコードが今の自分には一番しっくり来ました。
elseはifとセットという固定概念があったので、elseの使い方について勉強になりました。引き続きよろしくお願い致します。

お礼日時:2020/02/27 01:09

問題は該当項目があって数量加算した際に、加算した事を次に教えないからbreakしても追加をしちゃうんじゃないの?


だからそのチェック体制をすればよいかと思います。

data = ['cat','dog','cat','cat','car','dog','car','cat','cow','cat']
result=[]
for i in range (len(data)):
    ch = False
    for p in range (len(result)):
        if result[p][0] == data[i]:
            result[p][1] = result[p][1]+1
            ch = True
            break
    if ch == False:result.append([data[i],1])
print(result)

結果:

[['cat', 5], ['dog', 2], ['car', 2], ['cow', 1]]
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
返信遅れてすみません。
他の方にelseを使ったコードを教えて頂いてそれが分かりやすかったと思いましたが、なるほどチェック体制をつくるという代替案もあるのですね。私の知識でも書けたはずなだけに、とても勉強になりました。

お礼日時:2020/02/27 01:03

下のコードだと result[p][0] == data[i] が成り立っても result.append([data[i],1]) は処理しちゃうよ.



とはいえ, 本当にその結果になっているんだとしたらインデントもおかしい気がする. break が if の制御を受けていないような感じ.
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
実行結果ですが、
[['cat', 5], ['dog', 2], ['cat', 1], ['cat', 1], ['car', 2], ['dog', 1], ['car', 1], ['cat', 1], ['cow', 1], ['cat', 1]]
でした、失礼しました。
最初のコードの様に関数としてまとめてreturnにすれば処理を中止してくれるのと同じことをbreakでしたいのですが。
インデントはずらして動作確認しましたが、うまくいきませんでした。
breakなしで動かすと、
[['cat', 5], ['dog', 2], ['cat', 4], ['cat', 3], ['car', 2], ['dog', 1], ['car', 1], ['cat', 2], ['cow', 1], ['cat', 1]]
という結果になります。

お礼日時:2020/02/18 08:23

自分はよく知らないのですが、


 ・breakを有効にする宣言がされていない。
 ・breakはキー操作を受けて動作する。
なんて言語もあったので、これに該当しませんか?
あるいは、プログラムを無条件で中断する場合は「break」と一緒に「pause系」のコマンドを使うとか?
    • good
    • 0
この回答へのお礼

ご回答ありがとうございます。
Pythonではfor文のループを中断するのにbreakを入力するだけ良いはずです。
コマンドとかは特に必要ないです。
インデントさえ正しければ、ちゃんと動作します。

お礼日時:2020/02/18 08:16

お探しのQ&Aが見つからない時は、教えて!gooで質問しましょう!