リストに対する処理の書き方を言語ごとに比べてみる

これまでずっとjava7を触り続けてて、ふと他の言語でこの処理を書いた場合どう変わるんだろう？と思ったのでちょっと考えてみる。  
ってことでwebアプリだとありがちな配列の処理をお題に考えてみた。

## 要件

↓のjsonないしmapのリストを年齢>25に絞り、その後年齢の昇順ソートをする

```json
[
  {"age":25, "name": "adam"},
  {"age":60, "name": "adamo"},
  {"age":30, "name": "larry"}
]
```

## ケース1: Python(2.7)

pythonは高階関数が組み込み関数で定義されてるので書いてると徐々にネストが深くなっていく。  
そのせいもあって、こんなソースでも何に対してどんな配列処理をしてるのかだいぶ分かりづらい。

```py

users= [
  {"name":"adam","age":25},
  {"name":"adamo","age":60},
  {"name":"larry","age":30}
]

sorted(
  filter(lambda a: a['age']>25,
    users
  ),
  key=lambda a:a['age']
)
```

## ケース2: Python(2.7)他のアプローチ

partialを用いてカリー化を行い、reduceを用いたメソッドチェーンを行ってる。これだけでやるとなんともピンとこない感じだけど、xrangeみたいにメソッドを返すことで評価を後回しに出来るやつだと捗るのかもしれない。

```py
from functools import partial
def chain(*args):
   return reduce(lambda x,f:f(x), args)

filter25 = partial(filter, lambda a: a['age']>25)
sortbyage = partial(sorted, key=lambda a:a['age'])

users=[
  {"name":"adam","age":25},
  {"name":"adamo","age":60},
  {"name":"larry","age":30}
]
chain(
  users,
  filter25,
  sortbyage
)
```


## ケース3: scala

シンプル。

```scala
val users: List[Map[Symbol,String]] = List(
  Map('age->"25", 'name->"adam"),
  Map('age->"60", 'name->"adamo"),
  Map('age->"30", 'name->"larry")
)
users.filter(n => n.get('age).get.toInt > 25)
.sortBy(_.get('age).get)
```

Mapのままやると安全性を欠く。
最初の時点でクラスの配列に置き直すか途中でマッピングするかするといいと思う。

```scala
// 最初から変更するパターン
val users: List[Person] = List(
  new Person(25, "adam"),
  new Person(60,"adamo"),
  new Person(30,"larry")
)
users.filter(n => n.age > 25)
.sortBy(_.age)
```

```scala
// 途中で変更するパターン
val users: List[Map[Symbol,String]] = List(
  Map('age->"25", 'name->"adam"),
  Map('age->"60", 'name->"adamo"),
  Map('age->"30", 'name->"larry")
)
users.map(n => new Person(n('age).toInt, n('name)))
.filter(n => n.age > 25)
.sortBy(_.age)
```

## ケース4: java7 with guava:

実際こんなソースを書いてきた人がいた。guavaの知識があればいくらか分かりやすいものではあるけど……。
適当に書いてたので気付いたらクラス使ってしまった。pythonのそれと要求がずれてる。

```java
List<Map<String, String>> users = ImmutableList.of<Map<String, String>>(
        ImmutableMap.of("name", "adam", "age", "25"),
        ImmutableMap.of("name", "adamo", "age", "60"),
        ImmutableMap.of("name", "larry", "age", "30")
);
FluentIterable
.from(users)
.transform(new Function<Map<String, String>, Person>(){
    @Override
    public Person apply(Map<String,String> map){
        return new Person(map.get("name"), new Integer(map.get("age")));
    }
})
.filter(new Predicate<Person>(){
    @Override
    public boolean apply(Person person){
        return person.age > 25;
    }
})
.toSortedImmutableList(Ordering.natural().onResultOf(
    new Function<Person, Integer>(){
        @Override
        public Integer apply(Person person){
            return person.age;
        }
    })
);
```


## ケース5: java8

ソートの部分が若干古臭い感じは否めない。  
最初のデータの定義がだいぶめんどくさい。一番いいやり方はどれなんだろう。

```java
List users = Collections.unmodifiableList(Arrays.asList(
    new HashMap<String, String>(){{put("age","25");put("name","adam");};},
    new HashMap<String, String>(){{put("age","60");put("name","adamo");};},
    new HashMap<String, String>(){{put("age","30");put("name","larry");};}
    )
);
users.stream()
.filter(a -> new Integer(a.get("age")) > 25)
.sorted((o1, o2) -> new Integer(o1.get("age")).compareTo(new Integer(o2.get("age"))))
.collect(Collectors.toList());
```

これも途中でオブジェクトに格納するとだいぶ素直な感じになった。

```java
List users= Collections.unmodifiableList(Arrays.asList(
    new HashMap<String, String>(){{put("age","25");put("name","adam");};},
    new HashMap<String, String>(){{put("age","60");put("name","adamo");};},
    new HashMap<String, String>(){{put("age","30");put("name","larry");};}
    )
)
users.stream()
.map(a -> new Person(new Integer(a.get("age")), a.get("name")))
.filter(a -> a.age > 25)
.sorted(comparing(Person::getAge))
.collect(Collectors.toList());
```

## オチ

こんな狭いものだけ見てだからどうした？って感じではあるけど、少なくとも改めてjava7は捨ててjava8に上げた方がいいなあって思った。

今回は書いてないけどjava7だからって普通に手続き型で進めてるとこんな配列処理でも｢ついでにここの書き込みもやっちゃお｣って副作用もりもりのコード書かれてなんとも言えない気分になるので、java8のstream APIでコード規約を作れるのはとても魅力。