以下の自作クラスがあります。
Java
1public class Model { 2 3 /** 時刻. */ 4 private LocalTime localTime; 5 /** 身長 */ 6 private int height; 7 /** 体重. */ 8 private int weight; 9 10 public Model(LocalTime localTime, int height, int weight) { 11 this.localTime = localTime; 12 this.height = height; 13 this.weight = weight; 14 } 15}
これをメインクラスでインスタンスを作成し、リストに入れて
時刻が重複しているものをある条件で削除したいのですがうまくできません。
ある条件は身長が低いほうを削除、身長が同じであれば体重が低いほうを削除。
身長も同じであれば、ランダムで1つ残す。
試しに以下のような感じで削除したのですが、リストの中身のオブジェクトが1つも残りませんでした。
どなたか教えて頂ける幸いです。
Java
1 List<Model> list = new ArrayList<>(); 2 3 Model a = new Model(LocalTime.of(0, 0), 60, 90); 4 Model b = new Model(LocalTime.of(0, 0), 60, 90); 5 Model c = new Model(LocalTime.of(12, 0), 65, 90); 6 Model d = new Model(LocalTime.of(12, 0), 70, 80); 7 Model e = new Model(LocalTime.of(15, 0), 80, 90); 8 Model f = new Model(LocalTime.of(15, 0), 80, 90); 9 10 list.add(a); 11 list.add(b); 12 list.add(c); 13 list.add(d); 14 list.add(e); 15 list.add(f); 16 17 for (int i = 0; i < list.size(); i++) { 18 if (list.get(i).getLocalTime() == list.get(i + 1).getLocalTime()) { 19 if (list.get(i).getTall() > list.get(i + 1).getTall()) { 20 list.remove(i + 1); 21 } else { 22 list.remove(i); 23 } 24 } 25 }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
回答6件
0
ベストアンサー
1つの時刻に対して1つのオブジェクトだけ対応付けるという事なので、Mapの出番かなと思います。
「削除する」ではなく、「条件に合うものだけを集めたものを新たに作成する」という事になりますが、扱いやすくなります。
まずModelクラスにComparableを実装しましょう。比較がやりやすくなります。
hope_mucciさんがすでに実装例を示していますが、ここは直感的に従いやすくするために、時刻・身長・体重が大きいものを「大きい」と判定するようにしましょう。そうすると、同じ時刻内では「最も大きい」ものだけ残ればいいことになります。
java
1public class Model implements Comparable { 2 // 中略 3 @Override 4 public int compareTo(Model o) { 5 int comp = this.localTime.compareTo(o.localTime); 6 if (comp != 0) return comp; 7 comp = Integer.compare(this.height, o.height); 8 if (comp != 0) return comp; 9 return Integer.compare(this.weight, o.weight); 10 }
Map作成に移ります。LocalTimeをキーとしたマップにし、被ったら比較して大きいほうを残します。
「ランダムに残す」の部分は、この3要素が同じであれば結局同じものになるので無視します。
java
1 Map<LocalDate, Model> map = new HashMap<>(); 2 for (Model m : list) { 3 map.merge(m.getLocalDate(), m, (v1, v2) -> v1.compareTo(v2) < 0 ? v2 : v1); 4 } 5 List<Model> list2 = new ArrayList<>(map.values());
投稿2021/08/30 16:56
総合スコア20669
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
課題解決の方針
- Java 16の
record
型を使ってModelを定義する - Collectorsの
groupingBy
によってLocalTimeが同じModelをグループ分けして、Listを作成する - グループ分けされたListをソートまたはリダクションしてModelを1件求める。削除ではなく採用。
- Optional<Model>が発生しないようにする
Model
record型でかつComparableを実装する。Comparableは降順に並ぶよう定義する
Java
1import java.time.LocalTime; 2 3public record Model(LocalTime localTime, int height, int weight) implements Comparable<Model> { 4 @Override 5 public int compareTo(Model o) { 6 int lt = this.localTime.compareTo(o.localTime); 7 if (lt != 0) return lt; 8 int ht = Integer.compare(this.height, o.height); 9 if (ht != 0) return -ht; 10 return -Integer.compare(this.weight, o.weight); 11 } 12}
グループ分けすると、LocalTimeをキーにList<Model>を値とするマップができあがる。マップの各リストを降順にソートして先頭の1件を取る。
Java
1import java.time.LocalTime; 2import java.util.List; 3import java.util.stream.Collectors; 4 5public class q356940 { 6 7 public static void main(String[] args) { 8 9 var list = List.of( 10 new Model(LocalTime.of(0, 0), 60, 90), 11 new Model(LocalTime.of(0, 0), 60, 90), 12 new Model(LocalTime.of(12, 0), 65, 90), 13 new Model(LocalTime.of(12, 0), 70, 80), 14 new Model(LocalTime.of(15, 0), 80, 90), 15 new Model(LocalTime.of(15, 0), 80, 91), 16 new Model(LocalTime.of(15, 0), 80, 90) 17 ); 18 19 var selected = list.stream() 20 .collect(Collectors.groupingBy(Model::localTime)) 21 .values().stream() 22 .flatMap(l -> l.stream().sorted().limit(1)) 23 .collect(Collectors.toList()); 24 25 selected.forEach(System.out::println); 26 27 } 28 29}
Collectors.minByを使うと簡単ですが、結果がOptional<Model>なので、それを避けるために、初期値を与えるリダクションを記述する必要があります。あるいは、OptionalのorElseを使う後処理を書くか。どちらも簡潔さは損なわれます。
投稿2021/08/31 07:35
総合スコア1089
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
既存のリストをあれこれいぢりまわすより、新しいリストをつくったほうがいいとおもいます。ということで、
リストからある条件のものを削除
という要件は満たしていませんが。
- 時間ごとに分ける
- 身長毎に分ける
- 身長の一番でかいのをとる
- 体重ごとに分ける
- 体重の一番でかいのをとる
- ランダムに一件選ぶ
# ま、自分向けにstreamのお勉強がてら書いてみました
java
1import java.time.LocalTime; 2import java.util.*; 3import java.util.stream.Collectors; 4 5public class xxHogege { 6 7 public static void main(final String[] args) throws Exception { 8 final List<Model> list = new ArrayList<>(); 9 10 Model a = new Model(LocalTime.of(0, 0), 60, 90); 11 Model b = new Model(LocalTime.of(0, 0), 60, 90); 12 Model c = new Model(LocalTime.of(12, 0), 65, 90); 13 Model d = new Model(LocalTime.of(12, 0), 70, 80); 14 Model e = new Model(LocalTime.of(15, 0), 80, 90); 15 Model f = new Model(LocalTime.of(15, 0), 80, 90); 16 17 list.add(a); 18 list.add(b); 19 list.add(c); 20 list.add(d); 21 list.add(e); 22 list.add(f); 23 list.add(new Model(LocalTime.of(15, 0), 66, 190)); 24 list.add(new Model(LocalTime.of(15, 0), 55, 290)); 25 26 System.out.println("------"); 27 System.out.println(list); 28 29 final Map<LocalTime, List<Model>> localtimeMap = 30 list.stream().collect(Collectors.groupingBy(x -> x.localTime)); 31 32 // System.out.println("------ localtimeMap"); 33 // System.out.println(localtimeMap); 34 35 final List<Model> newList = localtimeMap.values().stream().map(modelList -> { 36 // System.out.println("------ modelList"); 37 // System.out.println(modelList); 38 39 final TreeMap<Integer, List<Model>> heightMap = 40 new TreeMap(modelList.stream().collect(Collectors.groupingBy(x -> x.height))); 41 final List<Model> maxHeightList = heightMap.get(heightMap.lastKey()); 42 // System.out.println("------ maxHeightList " + heightMap.lastKey()); 43 // System.out.println(maxHeightList); 44 45 final TreeMap<Integer, List<Model>> weightMap = 46 new TreeMap(maxHeightList.stream().collect(Collectors.groupingBy(x -> x.weight))); 47 final List<Model> maxWeightList = weightMap.get(weightMap.lastKey()); 48 // System.out.println("------ maxWeightList " + weightMap.lastKey()); 49 // System.out.println(maxWeightList); 50 51 return maxWeightList.get(new Random().nextInt(maxWeightList.size())); 52 }).sorted(Comparator.comparing(x -> x.localTime)).collect(Collectors.toList()); 53 54 System.out.println("------ newList"); 55 System.out.println(newList); 56 } 57 58 public static class Model { 59 /** 時刻. */ 60 final LocalTime localTime; 61 /** 身長 */ 62 final int height; 63 /** 体重. */ 64 final int weight; 65 66 public Model(LocalTime localTime, int height, int weight) { 67 this.localTime = localTime; 68 this.height = height; 69 this.weight = weight; 70 } 71 72 @Override 73 public String toString() { 74 return Map.of("localTime", localTime, "height", height, "weight", weight).toString(); 75 } 76 77 @Override 78 public boolean equals(Object obj) { 79 return obj != null && this.getClass().equals(obj.getClass()) && this.localTime.equals( 80 ((Model) obj).localTime) && this.height == ((Model) obj).height 81 && this.weight == ((Model) obj).weight; 82 } 83 84 @Override 85 public int hashCode() { 86 return Objects.hash(localTime, height, weight); 87 } 88 } 89} 90//------ 91//[{localTime=00:00, height=60, weight=90}, {localTime=00:00, height=60, weight=90}, {localTime=12:00, height=65, weight=90}, {localTime=12:00, height=70, weight=80}, {localTime=15:00, height=80, weight=90}, {localTime=15:00, height=80, weight=90}, {localTime=15:00, height=66, weight=190}, {localTime=15:00, height=55, weight=290}] 92//------ newList 93//[{localTime=00:00, height=60, weight=90}, {localTime=12:00, height=70, weight=80}, {localTime=15:00, height=80, weight=90}]
投稿2021/08/31 01:07
編集2021/08/31 02:54総合スコア4041
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2021/08/31 02:39
2021/08/31 02:56
2021/08/31 03:24
2021/08/31 07:27
2021/08/31 08:52
0
データ処理にランダムを入れてくるのが新鮮ですので、そのままコード化してみます。
java
1import java.time.LocalTime; 2import java.util.ArrayList; 3import java.util.List; 4import java.util.Random; 5 6class Model { 7 /** 時刻. */ 8 final LocalTime localTime; 9 /** 身長 */ 10 final int height; 11 /** 体重. */ 12 final int weight; 13 14 public Model(LocalTime localTime, int height, int weight) { 15 this.localTime = localTime; 16 this.height = height; 17 this.weight = weight; 18 } 19 20 @Override 21 public String toString() { 22 return new StringBuilder(super.toString()) 23 .append("[localtime=").append(localTime) 24 .append(",height=").append(height) 25 .append(",weight=").append(weight) 26 .append("]").toString(); 27 } 28} 29 30public class Q356940 { 31 public static void main(String[] args) { 32 List<Model> list = new ArrayList<>(); 33 34 Model a = new Model(LocalTime.of(0, 0), 60, 90); 35 Model b = new Model(LocalTime.of(0, 0), 60, 90); 36 Model c = new Model(LocalTime.of(12, 0), 65, 90); 37 Model d = new Model(LocalTime.of(12, 0), 70, 80); 38 Model e = new Model(LocalTime.of(15, 0), 80, 90); 39 Model f = new Model(LocalTime.of(15, 0), 80, 90); 40 41 list.add(a); 42 list.add(b); 43 list.add(c); 44 list.add(d); 45 list.add(e); 46 list.add(f); 47 for(Model m : list) System.out.println(m); 48 49 Random random = new Random(); 50 for (int i = 0; i < list.size(); i++) { 51 for (int j = i+1; j < list.size(); j++) { 52 //時刻比較(どちらかが消える) 53 if (list.get(i).localTime == list.get(j).localTime) { 54 //身長比較(小さいほうが消える) 55 if (list.get(i).height > list.get(j).height) { 56 list.remove(j--); continue; 57 } else if (list.get(i).height < list.get(j).height) { 58 list.remove(i--); break; 59 } 60 //体重比較(軽いほうが消える) 61 if (list.get(i).weight > list.get(j).weight) { 62 list.remove(j--); continue; 63 } else if (list.get(i).weight < list.get(j).weight) { 64 list.remove(i--); break; 65 } 66 //どっちでもいい(ランダムに消える) 67 if (random.nextInt(2) == 0) { 68 list.remove(j--); continue; 69 } else { 70 list.remove(i--); break; 71 } 72 } 73 } 74 } 75 76 System.out.println("----"); 77 for(Model m : list) System.out.println(m); 78 } 79}
plain
1Model@73a28541[localtime=00:00,height=60,weight=90] 2Model@470e2030[localtime=00:00,height=60,weight=90] 3Model@3fb4f649[localtime=12:00,height=65,weight=90] 4Model@33833882[localtime=12:00,height=70,weight=80] 5Model@200a570f[localtime=15:00,height=80,weight=90] 6Model@16b3fc9e[localtime=15:00,height=80,weight=90] 7---- 8Model@73a28541[localtime=00:00,height=60,weight=90] 9Model@33833882[localtime=12:00,height=70,weight=80] 10Model@200a570f[localtime=15:00,height=80,weight=90]
投稿2021/08/30 18:30
編集2021/08/30 18:40総合スコア13168
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
0
このような場合、Model側にcompareTo
メソッドを実装してデータ同士の大小関係を比較するのが定石になります。
専用のインターフェースがあります。
https://docs.oracle.com/javase/jp/8/docs/api/java/lang/Comparable.html
java
1 /** 2 * 引数のModelと比較する。時刻、身長、体重の順で大小を比較する 3 * 正の値が返れば、this側のオブジェクトの方が大きい。 4 * 負の値が返れば、other側のオブジェクトの方が大きい。 5 */ 6 public int compareTo(Model other){ 7 // まず時刻の比較 8 int comp; 9 comp = this.localTime.compareTo(other.getLocalTime()); 10 if(comp != 0) 11 return comp; 12 // 時刻が同じ(compが0)の場合、身長で比較 13 comp = this.height - other.getHeight(); 14 if(comp != 0) 15 return comp; 16 // 身長も同じ(compが0)の場合、体重で比較 17 return this.weight - other.getWeight(); 18 }
Main側ではまずリスト中の2つの要素について時刻を比較し、異なっていたらそのまま残す。
同じであれば、上記作成したcompareToメソッドで身長、体重を比較し、小さい方を削除するようにすれば良いでしょう。
(これは元のリストが時刻でソートされていることが前提になります)
java
1 for (int i = 0; i < list.size()-1; i++) { 2 Model m1 = list.get(i); 3 Model m2 = list.get(i+1); 4 // 2つの時刻が違っていたらそのまま残す 5 if(!m1.getLocalTime().equals(m2.getLocalTime())){ 6 continue; 7 }else{ 8 // 時刻が同じだったら、compareToメソッドで身長、体重の大小を比較 9 int comp = m1.compareTo(m2); 10 // compが正ならm1が大きいのでm2を削除、、compが負ならm2が大きいのでm1を削除 11 if(comp > 0){ 12 list.remove(m2); 13 i--; 14 }else if(comp < 0){ 15 list.remove(m1); 16 i--; 17 }else{ 18 // 同じだったらランダムで削除とのことだが、実装が面倒なのでm1を削除する 19 list.remove(m1); 20 i--; 21 } 22 } 23 }
投稿2021/08/30 14:23
総合スコア4447
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。