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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Java

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

Q&A

解決済

2回答

3801閲覧

Java の stream().filterのcontainsの条件にListを指定したい

yamato55

総合スコア2

Java

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

0グッド

0クリップ

投稿2023/01/26 04:42

編集2023/01/26 04:44

前提

Javaでテニスの対戦表を作成するプログラムを作成しています。
ペアのリストから休憩になる人が含まれているペアを除いたリスト(pairs)を作成する部分で、休憩になる人の人数が変わった場合、今は休憩する人数のswitchで条件を分けています。(ソースコードの61行目〜101行目)

実現したいこと

stream().filter(p -> !p.getKey().contains(条件)) の 条件に休みの人リスト(List<Integer> rest)を何か一括で指定できる方法はないでしょうか?

Java

1case 2: 2 int r2_1 = rest.get(0); 3 int r2_2 = rest.get(1); 4 5 pairs = pairMap.entrySet().stream() 6 .filter(p -> !p.getKey().contains(r2_1)) 7 .filter(p -> !p.getKey().contains(r2_2)) 8 .filter(p -> p.getValue() == minpair) 9 .map(Map.Entry::getKey) 10 .collect(Collectors.toList());
  • そもそもこの手の処理だとStream使わない?
  • for文で休憩いなる人とペアをグルグル回さないと書けない?
  • きれいな書き方

上記等ありましたらご助言いただけると嬉しいです。

該当のソースコード

Java

1import java.util.List; 2import java.util.*; 3import java.util.stream.*; 4import java.util.stream.Collectors; 5 6class StreamFilterTest { 7 //ペアの組み合わせ作成用 8 static List<List<Integer>> combination(List<Integer> member, int k){ 9 List<List<Integer>> comb = new ArrayList<>(); 10 if(member.size() < k || member.size() <= 0 || k <= 0){ 11 comb.add(new ArrayList<>()); 12 return comb; 13 } 14 for(int i=0; i<=member.size()-k; i++){ 15 Integer p = member.get(i); 16 List<Integer> rest = new ArrayList<>(member); 17 rest.subList(0, i+1).clear(); 18 comb.addAll(combination(rest, k-1).stream().map(list ->{ 19 list.add(0, p); 20 return list; 21 }).collect(Collectors.toList())); 22 } 23 return comb; 24 } 25 26 public static void main(String[] args) { 27 //参加する人数 28 int M = 6; 29 //参加する人数のリスト 30 List<Integer> member = IntStream.range(0, M) 31 .boxed() 32 .collect(Collectors.toList()); 33 34 //ペアの全組み合わせ 35 List<List<Integer>> pairList = combination(member, 2); 36 37 //ペアが何回試合したかを保存するMapを作成 38 Map<List<Integer>, Integer> pairMap = new LinkedHashMap<>(); 39 40 //テスト用に回数を2に設定 41 pairMap = pairList.stream() 42 .collect(Collectors.toMap(l -> l, l -> 2)); 43 //テスト用に3ペアの回数を0に設定 44 pairMap.put(Arrays.asList(0, 1), 0); 45 pairMap.put(Arrays.asList(0, 2), 0); 46 pairMap.put(Arrays.asList(0, 3), 0); 47 System.out.println("pairMap " + pairMap); 48 49 //試合回数の最小値を取得 50 int minpair = Collections.min(pairMap.values()); 51 52 //休みの人のリスト 53 //List<Integer> rest = new ArrayList<>(); 54 //List<Integer> rest = new ArrayList<>(Arrays.asList(1)); 55 List<Integer> rest = new ArrayList<>(Arrays.asList(1, 4)); 56 //List<Integer> rest = new ArrayList<>(Arrays.asList(1, 3, 4)); 57 58 //次に選択できるペアのリスト 59 List<List<Integer>> pairs = new ArrayList<>(); 60 61 //休みの人以外で、試合回数が少ないペアのリストを作成 62 switch(rest.size()){ 63 case 1: 64 int r1 = rest.get(0); 65 66 pairs = pairMap.entrySet().stream() 67 .filter(p -> !p.getKey().contains(r1)) 68 .filter(p -> p.getValue() == minpair) 69 .map(Map.Entry::getKey) 70 .collect(Collectors.toList()); 71 break; 72 73 case 2: 74 int r2_1 = rest.get(0); 75 int r2_2 = rest.get(1); 76 77 pairs = pairMap.entrySet().stream() 78 .filter(p -> !p.getKey().contains(r2_1)) 79 .filter(p -> !p.getKey().contains(r2_2)) 80 .filter(p -> p.getValue() == minpair) 81 .map(Map.Entry::getKey) 82 .collect(Collectors.toList()); 83 break; 84 85 case 3: 86 int r3_1 = rest.get(0); 87 int r3_2 = rest.get(1); 88 int r3_3 = rest.get(2); 89 90 pairs = pairMap.entrySet().stream() 91 .filter(p -> !p.getKey().contains(r3_1)) 92 .filter(p -> !p.getKey().contains(r3_2)) 93 .filter(p -> !p.getKey().contains(r3_3)) 94 .filter(p -> p.getValue() == minpair) 95 .map(Map.Entry::getKey) 96 .collect(Collectors.toList()); 97 break; 98 99 default: 100 pairs = pairMap.entrySet().stream() 101 .filter(p -> p.getValue() == minpair) 102 .map(Map.Entry::getKey) 103 .collect(Collectors.toList()); 104 break; 105 } 106 107 System.out.println("rest " + rest + " min " + minpair + " pairs" + pairs); 108 } 109} 110

補足情報(FW/ツールのバージョンなど)

Java 12.0.1 2019-04-16

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

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

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

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

jimbe

2023/01/26 05:16

コードの極一部をどう書くか程度は、個人のプログラムなら(ストリームだろうが何だろうが)好きに書いて良いのでは。
yamato55

2023/01/26 05:21

コメントありがとうございます。 streamで書くのはやはり難しいですかね・・・ filterとcontainsを調べるより、for文を2個回して書く方が早い気がしてきました。
guest

回答2

0

ペアということで k=2 固定で Pair クラス作ってループさせるとこんな感じでしょうか。

java

1import java.util.*; 2 3class StreamFilterTest { 4 private static class Pair { 5 final int a, b; 6 Pair(int a, int b) { 7 if(a == b) throw new IllegalArgumentException("a == b"); 8 this.a = Math.min(a, b); 9 this.b = Math.max(a, b); 10 } 11 boolean includedIn(List<Integer> list) { 12 return list.contains(a) || list.contains(b); 13 } 14 @Override 15 public String toString() { 16 return "["+a+", "+b+"]"; 17 } 18 @Override 19 public int hashCode() { 20 return Objects.hash(a, b); 21 } 22 @Override 23 public boolean equals(Object obj) { 24 if(this == obj) return true; 25 if(obj == null) return false; 26 if(getClass() != obj.getClass()) return false; 27 Pair other = (Pair)obj; 28 return a == other.a && b == other.b; 29 } 30 } 31 32 //ペアの組み合わせ作成用 33 private static Map<Pair,Integer> combinationMap(int m, int initialValue) { 34 Map<Pair,Integer> map = new HashMap<>(); 35 for(int i=0; i<=m-2; i++) { 36 for(int j=i+1; j<m; j++) { 37 map.put(new Pair(i, j), initialValue); 38 } 39 } 40 return map; 41 } 42 43 //休みの人以外で、試合回数が少ないペアのリストを作成 44 private static List<Pair> nextPairs(Map<Pair,Integer> map, List<Integer> rest, int mingames) { 45 //次に選択できるペアのリスト 46 List<Pair> pairs = new ArrayList<>(); 47 //休みの人以外で、試合回数が少ないペアのリストを作成 48 for(Map.Entry<Pair,Integer> entry : map.entrySet()) { 49 Pair pair = entry.getKey(); 50 if(!pair.includedIn(rest) && entry.getValue() == mingames) { 51 pairs.add(pair); 52 } 53 } 54 return pairs; 55 } 56 57 public static void main(String[] args) { 58 //参加する人数 59 int M = 6; 60 61 //ペアが何回試合したかを保存するMapを作成(テスト用に回数を2に設定) 62 Map<Pair, Integer> pairMap = combinationMap(M, 2); 63 //テスト用に3ペアの回数を0に設定 64 pairMap.put(new Pair(0, 1), 0); 65 pairMap.put(new Pair(0, 2), 0); 66 pairMap.put(new Pair(0, 3), 0); 67 System.out.println("pairMap " + pairMap); 68 69 //試合回数の最小値を取得 70 int mingames = Collections.min(pairMap.values()); 71 72 //休みの人のリスト 73 //List<Integer> rest = new ArrayList<>(); 74 //List<Integer> rest = new ArrayList<>(Arrays.asList(1)); 75 List<Integer> rest = Arrays.asList(1, 4); 76 //List<Integer> rest = new ArrayList<>(Arrays.asList(1, 3, 4)); 77 78 List<Pair> pairs = nextPairs(pairMap, rest, mingames); 79 80 System.out.println("rest " + rest + " min " + mingames + " pairs" + pairs); 81 } 82}

実行結果

pairMap {[1, 4]=2, [0, 5]=2, [1, 5]=2, [2, 5]=2, [0, 4]=2, [3, 4]=2, [0, 3]=2, [4, 5]=2, [0, 2]=0, [0, 1]=0, [1, 3]=2, [1, 2]=2, [2, 3]=2, [2, 4]=2, [0, 3]=0, [0, 1]=2, [0, 2]=2, [3, 5]=2} rest [1, 4] min 0 pairs[[0, 2], [0, 3]]

投稿2023/01/26 06:58

編集2023/01/26 16:13
jimbe

総合スコア12648

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamato55

2023/01/26 07:15

pairクラスを作っての回答ありがとうございます。 pairクラスを作るという発想がありませんでした!! このfor文は見やすくていいですね!! 今後ともどうぞよろしくお願いいたします。
jimbe

2023/01/26 16:14 編集

for である程度簡単になれば、ストリームも例えば List<Pair> pairs = pairMap.entrySet().stream() .filter(p -> !p.getKey().includedIn(rest) && p.getValue() == mingames) .map(Map.Entry::getKey) .collect(Collectors.toList()); と簡単になるのではないでしょうか。 フィルターの式がメソッドになるだけですけど。
yamato55

2023/01/26 07:55

メソッドを作るという発想がなかったです。 List同士をゴリゴリと無理矢理やろうとしているのが、あまりよろしくないのかも知れませんね・・・ 勉強になります!!!
guest

0

ベストアンサー

連続するfilterメソッドチェインは論理積(AND)と等価ですから、複雑な述語をもつ単一filter操作に合成可能です。

java

1pairs = pairMap.entrySet().stream() 2 .filter(p -> 3 !p.getKey().contains(r2_1) && !p.getKey().contains(r2_2) 4 && p.getValue() == minpair) 5 .map(Map.Entry::getKey) 6 .collect(Collectors.toList());

あとは !p.getKey().contains(r2_1) && !p.getKey().contains(r2_2) 部を「リスト中からの探索」コードに書き換えればよいのではないでしょうか。


追記:おそらく同じ動きをする述語にまとめたバージョンです。可読性が良いかどうかはお任せします :P

java

1pairs = pairMap.entrySet().stream() 2 .filter(p -> rest.stream().noneMatch(n -> p.getKey().contains(n))) 3 .filter(p -> p.getValue() == minpair) 4 .map(Map.Entry::getKey) 5 .collect(Collectors.toList());

投稿2023/01/26 05:33

編集2023/01/26 05:45
yohhoy

総合スコア6191

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yamato55

2023/01/26 05:44

回答ありがとうございます。 質問の仕方が悪くて申し訳ありません。 restリストのサイズが参加者と参加できる人数によって可変なので、restリストのサイズによってcase文を書いているのですが、case 10まで書くのは面倒だな・・・というのが正直な気持ちです。 pairMapのstreamのなかでrestのstreamを呼び出してフィルターして、最後にcollectでくっつけてみたいなことができないかな・・・と思った次第です。
yohhoy

2023/01/26 05:48

!p.getKey().contains(rest[0]) && ... && !p.getKey().contains(rest[N]) を rest.stream().noneMatch(n -> p.getKey().contains(n))) のように記述できることを利用し、回答に追記しました。
yamato55

2023/01/26 05:53

動きました! streamの中でstreamの呼び出しできるんですね。 勉強になりました。 ありがとうございました!!!
yohhoy

2023/01/26 05:55

> streamの中でstreamの呼び出しできる はい。 正確には「A.stream() の要素操作として 別のB.stream() を使える」と解釈したほうが良いですね。 見た目はことなりますが、やっていることは単純な 2重forループ構造 と同じです。
yamato55

2023/01/26 07:07

A.stream() の要素操作として 別のB.stream() を使える」なんですね! 今Stream APIを勉強中なので、できればfor文ではなくてstreamでできないかなと思って質問しました。 Stream APIはまだまだ奥が深いです。 今後ともどうぞよろしくお願いいたします。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問