質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.34%

  • Java

    14387questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Eclipse

    1738questions

    Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

  • Struts

    188questions

    StrutsはJava向けのWebアプリケーションフレームです。MVCモデルに基づいており、JSPやJavaサーブレットを組み合わせ、アプリケーション構築時に使用する各機能を提供しています。

二つのListを比較して違いがあれば行単位で抽出したい

解決済

回答 4

投稿 編集

  • 評価
  • クリップ 0
  • VIEW 2,484

pingu612

score 7

前提・実現したいこと

マスタとなるExcelを読み取って生成した二つのListを1行ずつ比較して、要素に違いがあれば行単位で抽出したいです。
上期マスタ:empPostList
下期マスタ:empLastPostList です。

抽出パターンは以下の通りです。
①上期マスタにあって下期マスタにない行(追加分)
②下期マスタにあって上期マスタにない行(削除分)
③変更のない行

発生している問題・エラーメッセージ

思いつく方法で比較をしてみましたが、
全行変更なしとして抽出されてしまいます。

※1/26追記
Excelから生成したListに問題があったようで、現在試すと
仰る通りほとんど「削除」に入っていく状態です。
「削除」部分のelse ifを削ると「変更なし」と「変更あり」については期待通りの動作をしています。
「削除」(下期マスタにあって上期マスタにない行)の抽出方法を模索しているところです。
elseで対応してみたりしましたが、どうにもうまくいかない状況です。。

該当のソースコード

            //「変更なし」格納用List
            ArrayList<EmpPostBean> noChange = new ArrayList<EmpPostBean>();
            // 「変更あり」格納用List
            ArrayList<EmpPostBean> Change = new ArrayList<EmpPostBean>();
            // 「削除用」格納用List
            ArrayList<EmpPostBean> Del = new ArrayList<EmpPostBean>();



            // 上期マスタ
            for (EmpPostBean This : empPostList) {
                // 下期マスタ
                for (EmpPostBean Last : empLastPostList) {
                    // 年、期、従業員ID、役職コードがすべて一致する場合
                    if (This.getYear().equals(Last.getYear())&&This.getTerm().equals(Last.getTerm())&&This.getDscId().equals(Last.getDscId())&&This.getPostCode().equals(Last.getPostCode())) {
                        noChange.add(This);
                        System.out.println("変更なしの行数:" + noChange.size());

                        break;

                    // 従業員IDが一致し、役職コードが不一致の場合
                    }else if(This.getDscId().equals(Last.getDscId())&& !This.getPostCode().equals(Last.getPostCode())){
                        Change.add(This);
                        System.out.println("変更ありの行数:" + Change.size());

                        break;

                    // 従業員IDが一致しないが、役職コードがNULLでない場合
                    }else if(!This.getDscId().equals(Last.getDscId())&& This.getPostCode().isEmpty()|| Last.getPostCode().isEmpty()){
                        Del.add(This);
                        System.out.println("削除の行数:" + Change.size());

                        break;
                    }
                }
            }

※1/26追記
HashMapを使う方法を試行してみました。
今度は削除分はうまく動作しましたが、「変更なし」分が取れていないみたいです。
キーが一致したifに入った場合、更にif文でValue値のチェックを行っており、そこでcontainsValueがtrueになればキーもValue値も一致することになるので、「変更なし」に追加すると記述したつもりです。
ご指摘あればよろしくお願いします。

            // 今期マスタをHashMapに詰める
             Map<String, EmpPostBean> Thismap = new HashMap<String, EmpPostBean>();
             for (EmpPostBean This : empPostList) {

                 // キーと値をセット
                 Thismap.put(This.getDscId(),This);
             }

            // 前期従業員マスタの要素がHashMapに含まれていれば変更なしリストに追加する
             for (EmpPostBean This : empLastPostList) {

                 // キーが一致
                 if(Thismap.containsKey(This.getDscId())) {
                     // 役職コードが一致
                     if(Thismap.containsValue(This.getPostCode())){
                         //変更なしリストに追加
                         noChange.add(This);
                         System.out.println("変更なしの行数:" + noChange.size());

                     // 役職コードが不一致
                     }else{
                     // 変更ありリストに追加
                     Change.add(This);
                     System.out.println("変更ありの行数:" + Change.size());
                     }
                 }else{

                     Del.add(This);
                     System.out.println("削除の行数:" + Del.size());
                 }
            }

試したこと

・比較を行う際、equalsでなく「==」で試してみる
・HashMapを使って比較してみる
→キー指定が分からず断念しています。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • swordone

    2017/01/26 10:37

    全行「変更なし」なのですか?これ冷静に考えるとほとんどが「削除」に入りそうなのですが…

    キャンセル

回答 4

+2

ちょっと要件が不明なところがありますが、2つのListの要素が一致しているものだけを抽出した新しいListを作成するのであれば、EmpPostBeanでequalsとhashCodeメソッドを適切に実装したうえで、以下のコードだけで済みませんか?

ArrayList<EmpPostBean> noChange = empPostList.stream()
    .filter(o -> empLastPostList.contains(o))
    .collect(Collectors.toList());

dscIdが同じでpostCodeが異なるものだけを抽出するのであれば以下のようになります。

ArrayList<EmpPostBean> Change = empPostList.stream()
    .filter(o -> empLastPostList.stream()
        .anyMatch(o2 -> o.getDscId().equals(o2.getDscId()) && 
                       !o.getPostCode().equals(o2.getPostCode())))
    .collect(Collectors.toList());

3つ目の要件ですが、書かれているコードの条件式おかしくないですか?
ちなみにisEmptyはnull判定用のメソッドではありません。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/26 10:16

    ご回答ありがとうございます。
    streamメソッドの実装を試みましたが、JDKのバージョンが古いため実装出来ませんでした。
    都合によりJDKのバージョンを変更できないため、別の方法を模索するしかないようです。
    null判定についてご指摘ありがとうございます、仰る通りでした。。

    キャンセル

checkベストアンサー

+1

1行ごとに各if条件をチェックするので、1行目でIDが一致しなければ、仮にほかの行で一致するものがあったとしても「削除」と判定されてしまいます。
なのでこの方法でやるとしたら、内側のforを抜けた後で削除リストへの追加を行うべきです。
「empPostListからの要素で、empLastPostListにIDが同じものがなかった」という状態ですから。

HashMapのキー値が思いつかなかったということですが、変更・追加・削除の基準が従業員IDなので、それをキーにしてしまえばいいのです。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/26 11:26

    ご回答ありがとうございます。
    内側forを抜けた後に削除リストへの追加を試してみたいと思います。

    HashMapの方は従業員IDをキーにして、残りを値とするところまでは理解できました。
    キーが一致していて、値が一致→変更なしリストに追加
    キーが一致していて、値が一部違った場合(具体的には役職コード)→変更ありリストに追加
    キーが一致しない→削除リストに追加
    ということでしょうか?

    キャンセル

  • 2017/01/26 11:50

    そうですね。ただし「追加分(前なかったが今ある)」の処理ができないので、逆パターンで処理するか、全体をデザインしなおすかですね。

    キャンセル

  • 2017/01/26 12:20

    あ、フラグを用意しておかないと必ず削除に入っちゃうことに今気づいた

    キャンセル

  • 2017/01/26 16:49

    ご回答ありがとうございます。
    追加分については逆パターンで処理をしてみようと思います。
    HashMapを使った処理に書き直してみましたが、削除分はContainKeyのElseで処理を行っています。
    追加分をContainValueで処理したところ、ifに入らずうまく比較が出来ていないようです。
    コードを記載してみたので、ご指摘いただけますでしょうか?

    キャンセル

  • 2017/01/26 23:58

    格納している値はEmpPostBean型なのですから、その中のgetPostCode()でえられる値がマップの値として入っているわけがありません。マップに対してキーを使ってget()し、それに対してgetPostCode()を実行しないと検証できません。

    キャンセル

  • 2017/01/27 16:20

    ありがとうございます。
    Mapの生成方法とif文の判定条件を見直した後、期待通りに挙動しました!

    キャンセル

+1

プログラムにこだわるのでなければ、diff でもとれば済みそうな……
それはさておき、概念的にはこんなところでしょうか。

int firstIdx = 0;
int secondIdx = 0;
while(true) {
  // ループ脱出チェック
  if (firstIdxがempPostListの件数以上になるか、secondIdxがempLastPostListの件数以上になる) {
    break;
  }
  // 双方を取り出す
  empPostBean firstBean = empPostList[firstIdx];
  empPostBean secondBean = empLastPostList[secondIdx];
  // 比較
  if (firstBeanとsecondBeanが一致) {
    // TODO: 一致のリストに入れる
    firstIdx++;
    secondIdx++;
  } else if (firstBeanの方がsecondBeanより小さい = 前期にあり後期にない) {
    // TODO: 前期のみのリストに入れる
    firstIdx++;
  } else if (firstBeanの方がsecondBeanより大きい = 後期にあり前期にない) {
    // TODO: 後期のみのリストに入れる
    secondIdx++;
  }
}
// TODO: 前期側リストの末尾まで行っていなければ、残りをすべて前期のみのリストに入れる
// TODO: 後期側リストの末尾まで行っていなければ、残りをすべて後期のみのリストに入れる

リストのそれぞれの着目位置を独立して制御するわけです。Excel で二つのシートを並べ、上から1行ずつ比較していくイメージですね。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/26 11:22

    ご回答ありがとうございます。
    リストのインデックス位置を見て判断しているということでしょうか?
    そういう考え方は盲点でした。ちょっと試行してみます。
    ありがとうございます!

    キャンセル

0

方向性は合ってるのでif文の条件判定がきちんと動作してないのではないでしょうか。
一個一個ブレークポイント張ってデバッグでとめて変数の中身を確認しながらきちんと条件を通るか確認してみれば自力でいけませんか。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2017/01/27 16:21

    ご回答ありがとうございます。
    仰る通り、条件判定の部分がきちんと動いていませんでした。
    containsValueで判定していたことが原因で、Mapのキーを使ってValueを取得したところ、正しく判定ができました。
    ありがとうございます!

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.34%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る

  • Java

    14387questions

    Javaは、1995年にサン・マイクロシステムズが開発したプログラミング言語です。表記法はC言語に似ていますが、既存のプログラミング言語の短所を踏まえていちから設計されており、最初からオブジェクト指向性を備えてデザインされています。セキュリティ面が強力であることや、ネットワーク環境での利用に向いていることが特徴です。Javaで作られたソフトウェアは基本的にいかなるプラットフォームでも作動します。

  • Eclipse

    1738questions

    Eclipseは、IBM社で開発された統合開発環境のひとつです。2001年11月にオープンソース化されました。 たくさんのプラグインがあり自由に機能を追加をすることができるため、開発ツールにおける共通プラットフォームとして位置づけられています。 Eclipse自体は、Javaで実装されています。

  • Struts

    188questions

    StrutsはJava向けのWebアプリケーションフレームです。MVCモデルに基づいており、JSPやJavaサーブレットを組み合わせ、アプリケーション構築時に使用する各機能を提供しています。