レスポンスデータを加工する（拡張for文）

## はじめに
レスポンスデータって全要素使うわけではなかったり、ネスト構造になってたり、結構見にくいことが多いと思います。
ということで取得したレスポンスを加工(フィルター, マッピング, ソート)して、自分好みのデータクラスを作成してみました。

## ゴール
フィルター（抽出）：likeCountが5より大きいもの
マッピング（結合）：title,body,likeCount,name
ソート（並び替え）：likeCountで降順

|加工前|加工後|
|----|----|
|![スクリーンショット 2021-03-16 22.02.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670405/f5eee0bb-25e2-cbf1-addf-6f8de6535538.png)|<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/670405/95e30cc0-cae8-4904-887a-3077ba2d8e46.png" width=100%>|


## 実装
※コード長くなるため、API使わずにレスポンスを模した自作の簡易データを使ってます。
### 加工前データクラス定義
使用しないゲッター、セッターは省略してます

```java:ArticleResponse.java
public class ArticleResponse {
    private String title;
    private String body;
    private String createdAt;
    private int likeCount;
    private User user;

    public ArticleResponse(String title, String body, String createdAt, int likeCount, User user) {
        this.title = title;
        this.body = body;
        this.createdAt = createdAt;
        this.likeCount = likeCount;
        this.user = user;
    }

    public String getTitle() {
        return title;
    }

    public String getBody() {
        return body;
    }

    public int getLikeCount() {
        return likeCount;
    }

    public User getUser() {
        return user;
    }
}
```

```java:User.java
public class User {
    private String name;
    private int id;
    private int followeesCount;
    private int followersCount;

    public User(String name, int id, int followeesCount, int followersCount) {
        this.name = name;
        this.id = id;
        this.followeesCount = followeesCount;
        this.followersCount = followersCount;
    }

    public String getName() {
        return name;
    }
}
```
### 加工データクラス定義
使用しないゲッター、セッターは省略してます

```java:ArticleBusinessModel.java
public class ArticleBusinessModel {
    private String title;
    private String body;
    private int likeCount;
    private String name;


    public ArticleBusinessModel(String title, String body, int likeCount, String name) {
        this.title = title;
        this.body = body;
        this.likeCount = likeCount;
        this.name = name;
    }

    public int getLikeCount() {
        return likeCount;
    }
}
```

### データを加工
```java:ArticleRepository.java
public class ArticleRepository {
    
    private ArrayList<ArticleResponse> responses = sampleResponseData();  // 加工前のサンプルデータ

    public List<ArticleBusinessModel> mapping() {
        List<ArticleBusinessModel> processedData = new ArrayList<ArticleBusinessModel>();
        for (ArticleResponse article : responses) {
            if (article.getLikeCount() > 5) {
                processedData.add(new ArticleBusinessModel(
                        article.getTitle(),
                        article.getBody(),
                        article.getLikeCount(),
                        article.getUser().getName())
                );
            }
        }

        // 並び替え
        processedData.sort(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed());

        // 中身見るためにJsonに変換
        Gson gson = new Gson();
        Log.i("元データ：", gson.toJson(responses));
        Log.i("加工データ：", gson.toJson(processedData));

        return processedData;
    }

    // サンプルデータ作成
    private ArrayList<ArticleResponse> sampleResponseData() {
        ArrayList<ArticleResponse> dataList = new ArrayList<>();

        User user1 = new User("Ichiro", 1, 70, 50);
        User user2 = new User("Jiro", 2, 40, 10);
        User user3 = new User("Saburo", 3, 20, 5);
        User user4 = new User("Shiro", 4, 10, 5);

        dataList.add(new ArticleResponse("Java", "静的型付け言語です", "2021/3/1", 10, user1));
        dataList.add(new ArticleResponse("Ruby", "動的型付け言語です", "2021/3/2", 8, user2));
        dataList.add(new ArticleResponse("Swift", "静的型付け言語です", "2021/3/2",14, user3));
        dataList.add(new ArticleResponse("NoCode", "ノーコードです", "2021/3/3", 3, user4));

        return dataList;
    }
}
```
#### 【解説】データをソート
```java
processedData.sort(Comparator.comparing(ArticleBusinessModel::getLikeCount).reversed());
```
* ポイント
 * Comparatable.comparing(クラス名::値) で指定の値で比較することできる
 * reversed()で降順

#### 【解説】データをフィルターしてマッピング(普通のfor文の場合)
```java
    // memo: ArrayList<ArticleResponse> responses = sampleResponseData();

    // // 加工データを格納する入れ物を用意
    List<ArticleBusinessModel> processedData = new ArrayList<ArticleBusinessModel>();

    for (int i = 0; i < responses.size(); i++ ) {
        if (responses.get(i).getLikeCount() > 5) {
            processedData.add(new ArticleBusinessModel(
                    responses.get(i).getTitle(),
                    responses.get(i).getBody(),
                    responses.get(i).getLikeCount(),
                    responses.get(i).getUser().getName())
            );
        }
    }
```
これでもいいのですが、拡張for文を使うともっとスマートに書けます。

#### 拡張for文について
複数要素をもつ配列やコレクションに対して、要素を1つずつ順番に取り出して処理をしてくれます。

* 拡張for文の書き方

```java
for (型名 変数名 : 配列名) {}
```
* 拡張for文の使い所
  * リスト内のすべての要素に対して１つずつ繰り返し処理をするとき
  * リストの何番目が必要という要件がないとき（順番関係なく処理したいとき）

#### 【解説】データをフィルターしてマッピング(拡張for文の場合)
```java
    // memo: ArrayList<ArticleResponse> responses = sampleResponseData();

    // 加工データを格納する入れ物を用意
    List<ArticleBusinessModel> processedData = new ArrayList<ArticleBusinessModel>();

    for (ArticleResponse article : responses) {
        if (article.getLikeCount() > 5) {
            processedData.add(new ArticleBusinessModel(
                    article.getTitle(),
                    article.getBody(),
                    article.getLikeCount(),
                    article.getUser().getName())
            );
        }
    }
```

### データ加工を実行
本来はViewModelを経由すべきだがコード長くなるので割愛

```java:MainActivity.java
public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        ArticleRepository articleRepository = new ArticleRepository();
        articleRepository.mapping();
        
    }
}
```

## 最後に
次回はStreamを使ってデータ加工する方法を紹介。
[レスポンスデータを加工する（Stream）](https://qiita.com/kilalabu/items/cc22c6fb01eec77b3756)

## 参考URL
https://qiita.com/takahirocook/items/470b2858de1a4f99b334
https://cartman0.hatenablog.com/entry/2016/02/29/032507
ありがとうございました！