human
6. Exercise: オブジェクト指向プログラミングと関数型プログラミング (OOP and FP
<!--
```
# ASSIGNMENT METADATA
assignment_id: "FP_OOP"
```
-->

lang:ja
この節では、ここまでで学んだ関数型プログラミング的考え方と、classを用いるオブジェクト指向的考え方をあわせて、データ処理を行うプログラムを書いてみましょう。
今回は"('市町村名', 人口, 面積)" というタプルのリストに対する処理をするプログラムを考えます。
6.1-6.3が問題の説明、6.4で実装という構成になっています。
lang:en
In this section, let's write a program that performs data processing, combining the functional programming and the object-oriented programming.
Here, let's consider a program that operates on a list of tuples " ('city name', population, area) ".
Problem statements are given in 6-1, 6-2, and 6-3, and you can implement the solution in 6-4.
```python
[(city name, population, area)]
test_data = [('Chiyoda',   64894, 11.66),
             ('Minato',   259042, 20.37),
             ('Shinjuku', 349844, 18.22),
             ('Bunkyo',   233926, 11.29),
             ('Taito',    207838, 10.11)]
```
6.1. Define a class
lang:ja
一つの市町村のデータを表すクラス City を実装してください。
このクラスは
* name
* population
* area
というメンバーをもち、これらの値をタプルとして受け取るコンストラクタを持つようにしてください。
lang:en
Define a class City, which has the following members:
* name
* population
* area
The City has to have a contstructor that work like followings:
Example
```python
name = 'Bunkyo'
population = 233926
area = 11.29
city = City((name, population, area))
assert(city.name == name)
assert(city.area == area)
assert(city.population == population)
You can create a list of City instances from test_data by using map.
city_list = list(map(City, test_data))
```
6.2. Define a method
lang:ja
6.1.で定義した class City に人口密度を計算して返すメソッド population_density() を実装してください。
lang:en
Implement a method population_density() in City
Example
```python
Population density is (population / area)
assert(city.population_density() == city.population / city.area)
```
6.3. Get top k cities
lang:ja
Cityのインスタンスのリスト city_list を受け取り、 人口密度が高い上位k個の都市の名前のリストを返す関数 top_k_densest_city_name(city_list, k) を実装してください。

注意： 返すリストの要素は都市の名前にして下さい。
実装のヒント: リストlに対し、l[n:m]と書くことで n番目からm-1番目の要素までを取り出すことが出来ます。

lang:en
Implement a function...
assistant
#Here is the Python program you requested.
%%solution

# [(city name, population, area)]
test_data = [('Chiyoda',   64894, 11.66),
             ('Minato',   259042, 20.37),
             ('Shinjuku', 349844, 18.22),
             ('Bunkyo',   233926, 11.29),
             ('Taito',    207838, 10.11)]
    
""" # BEGIN PROMPT    
class City:
  # Q 6.1.
  def __init__(self, data):
    pass

  # Q 6.2.
  def population_density(self):
    pass
    
# Q6.3.
def top_k_densest_city_names(city_list, k):
  pass
""" # END PROMPT

# BEGIN SOLUTION
class City:
  # Q 6.1.
  def __init__(self, data):
    self.name = data[0]
    self.population = data[1]
    self.area = data[2]

  # Q 6.2.
  def population_density(self):
    return self.population / self.area

# Q6.3.
def top_k_densest_city_names(city_list, k):
  sorted_cities = list(sorted(city_list, key=lambda c: c.population_density(), reverse=True))
  return list(map(lambda c: c.name, sorted_cities[:k]))
# END SOLUTION

%%studenttest FPAndOOPStudentTest1
# Q 6.1.

## Create a `City` instance for ('Chiyoda', 64894, 11.66) 
chiyoda_ku = City(test_data[0])

## Each data must be accessed 
assert(chiyoda_ku.name == 'Chiyoda')
assert(chiyoda_ku.population == 64894)
assert(chiyoda_ku.area == 11.66)

%%studenttest FPAndOOPStudentTest2

# Q 6.2.
## Population density is (population / area)
assert(chiyoda_ku.population_density() == 64894 / 11.66)

%%studenttest FPAndOOPStudentTest3

# Q 6.3.

## Create a list of `City` instances by using `map` function.
city_list = list(map(City, test_data))

## Get Top 5 cities
top5_densest_cities = top_k_densest_city_names(city_list, 5)

# Expected: ['Bunkyo', 'Taito', 'Shinjuku', 'Minato', 'Chiyoda']
print('Top 5 cities: {}'.format(top5_densest_cities))
assert(len(top5_densest_cities) == 5)

expected = ['Bunkyo', 'Taito', 'Shinjuku', 'Minato', 'Chiyoda']
assert top5_densest_cities == expected, 'Expected: {}, Actual: {}'.format(expected, top5_densest_cities)

%%studenttest FPAndOOPStudentTest3_2

# More tests: Change the value of `k`

## Get Top 2 cities
top2_densest_cities =...