第9章の解答。以下ネタバレなので、読みたくない方は立ち去りましょう。問題文は載せませんので悪しからず。必要なら買いましょう。その前にこの章の個人的なメモ。
- setオブジェクトで保持される順序にルールはない。
- 集合はハッシュテーブルというデータ構造に格納される。
- 集合の要素に対し、ハッシュコードが計算される。ハッシュコードはイミュータブル(書き換え不可能なデータ)のみ持つことが許される。
- 辞書の初期化は{}で行う。追加はappendなどではなく、辞書名[キー] = 値 という形式で指定すればOK。
- 185ページのdict_of_dicts.pyのサンプルコードに登場する辞書でJグドールに関する項目に'霊長類研究者'(英語では'primate researcher')とあるが、この後ろに「,」がないため、編集の必要がある。おそらくバグ。
1
# -*- encoding: sjis -*- def find_dups(data): h_table = {} for d in data: if d in h_table.keys(): # getメソッドを利用する方法もある h_table[d] += 1 else: h_table[d] = 1 ret = [] # iteritemsはオブジェクトのコピーを作らないので高速に動かすことができる for (key, value) in h_table.iteritems(): if value >= 2: ret.append(key) return ret if __name__ == '__main__': data = range(10) + range(10, 5, -1) + range(3, 7) ret = find_dups(data) print ret
2
def mating_pairs(males, females): ''' the size of males and that of females are the same. ''' ret = [] # while males: is OK. this answer is a bit copmlex. while len(males) > 0: ret.append((males.pop(), females.pop())) return set(ret) if __name__ == '__main__': males = set(['A', 'B', 'C', 'D', 'E']) females = set(['1', '2', '3', '4', '5']) print mating_pairs(males, females)
3
PDB形式のAUTHORの行に関する情報はこちらのpdfを参考にするとよいでしょう。人物名はコンマ区切り、AUTHORと人名は空白で区切られているという条件を使います。また、最後にコンマがあり人名が続かないこともありますので、そのようなことも考慮しています。
# -*- encoding: sjis -*- import sys def read_author(r): ret = set() for line in r: if not line: continue if line[:6].upper() != 'AUTHOR': # AuthorなどもOKにするため、upper()を挟んでいる continue # 仕様の都合上8文字目から作者名が始まる可能性がある。 # strip()でいったん両端の空白を削除してから","で区切る line = line[7:].strip().split(",") print line for i in range(len(line)): if not line[i]: # AUTHORとあるが、何も続かない場合 continue ret.add(line[i]) return ret # setを返しておく if __name__ == '__main__': names = set() for filename in sys.argv[1:]: # 外部からファイルを読み込みたい infile = open(filename, 'r') name = read_author(infile) names = names.union(name) # 和集合はunionである infile.close() print names
4(自信薄)
setの中に中身が変更可能なsetが入れられないのでfrozensetにして入れている。vowelは要素にfrozensetのデータを持つが、すでに通常のsetとして扱って問題ない。中身が書き換え可能なメモリアドレスにvowelsが配置されるということになる。
5
def count_values(dic): values = {} for (key, value) in dic.iteritems(): if not value in values: values[value] = 1 return len(values) if __name__ == '__main__': print count_values({'red':1, 'green':2, 'blue':3}) print count_values({'red':1, 'green':2, 'blue':1}) print count_values({'red':2, 'green':2, 'blue':2})
6
def min_elementary_particle(dic): minimum = 1.1 # probability is always smaller than 1 elem = '' for (key, value) in dic.iteritems(): if value < minimum: minimum = value elem = key return elem if __name__ == '__main__': component = {'neutrino':0.14 , 'neutron':0.55, 'proton':0.21, 'meson':0.03, 'muon':0.07} print min_elementary_particle(component)
7
def count_duplicates(dic): dup = {} for (key, value) in dic.iteritems(): if not value in dup: dup[value] = 1 else: dup[value] += 1 dup_list = [] for (key, value) in dup.iteritems(): if value >= 2: dup_list.append(key) return len(dup_list) if __name__ == '__main__': color = {'red':1, 'green':4, 'blue':2, 'orange':3, 'green':2, 'orange':6} print count_duplicates(color) # 2 is duplicated number.
8
例外という先の内容を無理やり利用しろということなので、試しに使ってみた。
def fetch_and_set(dic, key, new_value): if key in dic: old_value = dic[key] dic[key] = new_value return old_value else: raise KeyError("Unable to replace value for nonexistent key") if __name__ == '__main__': color = {'red':1, 'green':4, 'blue':2, 'orange':3} print fetch_and_set(color, 'green', 100) # 4 try: fetch_and_set(color, 'black', 3) # KeyError exception except KeyError: print "KeyError occurred!"
9
問題の仕様にはないのですが、辞書には必ずしもキーがR、G、Bだけではないものと仮定します。RGB以外は無視するものとします。
def is_balanced(dic): total = 0 for (key, value) in dic.iteritems(): if key == 'R' or key == 'G' or key == 'B': total += value if abs(total - 1.0) < 10 ** -15: # almost equal to 1 return True else: return False if __name__ == '__main__': color = {'R':0.1, 'G':0.4, 'B':0.5} print is_balanced(color) # True color = {'R':0.1, 'G':0.4, 'X':0.2, 'B':0.5} print is_balanced(color) # True color = {'R':0.1, 'G':0.4, 'B':0.2} print is_balanced(color) # False
10
両方の辞書に同じキーと同じ値が含まれている対のみ返します。同じキーだが値が違うという場合はdict_intersectの返り値の辞書には含まないものとします。
def dict_intersect(dic1, dic2): k2 = dic2.keys() ret = {} for (k1, v1) in dic1.iteritems(): if k1 in k2 and v1 == dic2[k1]: ret[k1] = v1 return ret if __name__ == '__main__': c1 = {'red':1, 'green':4, 'blue':2, 'orange':3, 'green':2, 'orange':6} c2 = {'red':1, 'green':5, 'blue':2, 'yellow ':3} print dict_intersect(c1, c2) # blue and red are extracted
11
scientists = { 'jgoodall' : {'surname' : 'Goodall', 'forename' : 'Jane', 'born' : 1934, 'died' : None, 'notes' : 'primate researcher', # distributed sample code lacks comma. 'author' : ['In the Shadow of Man', 'The Chimpanzees of Gombe']}, 'rfranklin' : {'surname' : 'Franklin', 'forename' : 'Rosalind', 'born' : 1920, 'died' : 1957, 'notes' : 'contributed to discovery of DNA'}, 'rcarson' : {'surname' : 'Carson', 'forename' : 'Rachel', 'born' : 1907, 'died' : 1964, 'notes' : 'raised awareness of effects of DDT', 'author' : ['Silent Spring']} } def db_headings(dic): ret = [] for values in dic.values(): ret += values.keys() return set(ret) if __name__ == '__main__': print db_headings(scientists)
12
scientistsは上のデータを利用することにします。rfranklinは他の二つとキーが異なるため内部の辞書は常に一定にはなりません。そのため、db_consistent関数にscientistsを渡すと、Falseになります。if elem.symmetric_difference(set(values)):は要素数が0でなければという意味になります。
def db_consistent(dic): first = dic.keys()[0] elem = set(dic[first].keys()) for values in dic.values(): if elem.symmetric_difference(set(values)): return False return True if __name__ == '__main__': print db_consistent(scientists)
13
空行で機能が大まかに区切られているので、それを1つのまとまりとしてモジュールにするというだけですね。
import sys def create_dic(files): count = {} for filename in sys.argv[1:]: infile = open(filename, 'r') for line in infile: name = line.strip() count[name] = count.get(name, 0) + 1 infile.close() return count def reverse_dict(dic): freq = {} for (name, times) in dic.iteritems(): print name, times if times in freq: freq[times].append(name) else: freq[times] = [name] return freq def print_dic(dic): for key in sorted(dic): print key for name in dic[key]: print ' ', name if __name__ == '__main__': dic = create_dic(sys.argv[1:]) r_dic = reverse_dict(dic) print_dic(r_dic)
14
a)、b)の解答は以下の通り。
def sparse_add(dic1, dic2): ret = dic1.copy() keys = set(dic1.keys() + dic2.keys()) for key in keys: ret[key] = 0 if key in dic1.keys(): ret[key] += dic1[key] if key in dic2.keys(): ret[key] += dic2[key] return ret def sparse_dot(dic1, dic2): ret = 0 for (key, value) in dic1.iteritems(): if key in dic2: ret += value * dic2[key] return ret if __name__ == '__main__': v1 = {0:1, 6:3, 7:-1} v2 = {1:1, 2:2, 6:1, 7:-1} print sparse_add(v1, v2) # {0: 1, 1: 1, 2: 2, 6: 4, 7: -2} print sparse_dot(v1, v2) # 4
c)に関しては、疎ベクトルの長さが、辞書の長さになるのか、それとも最後に現れた辞書のキーの値+1になるのかということが曖昧になっている。0を値に持つキーをどのように扱うかということが、「疎ベクトルの長さ」という言葉だけでははっきりしないということである。
0 件のコメント:
コメントを投稿