【Java】商品一覧をソートし、商品タイプごとにソート順が1位の商品を抽出する
実行環境
やりたいこと
- 商品一覧をソートする
- 商品タイプごとにソート順が1位の商品を抽出する
- 抽出結果をソートする
単一ソートの場合
- 価格の降順でソートする
- 商品タイプごとにソート順が1位の商品に絞る
【インプット】
商品名 | 商品タイプ | 価格 |
---|---|---|
N1 | T1 | 1000 |
N2 | T1 | 2000 |
N3 | T1 | 3000 |
N4 | T2 | 4000 |
N5 | T2 | 5000 |
N6 | T2 | 6000 |
N7 | T3 | 7000 |
N8 | T3 | 8000 |
N9 | T3 | 9000 |
【アウトプット】
商品名 | 商品タイプ | 価格 |
---|---|---|
N9 | T3 | 9000 |
N6 | T2 | 6000 |
N3 | T1 | 3000 |
【やり方】
- Collectors.groupingBy()で商品タイプごとにグルーピングする
- グルーピングする際にCollectors.maxBy()で価格が最も高い商品を抽出する
- グルーピング結果を価格の降順でソートする
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import org.junit.Test; import java.util.*; import java.util.stream.Collectors; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; public class SingleSortTest { // 商品 @Getter @ToString @AllArgsConstructor public class Item { // 商品名 private String name; // 商品タイプ private String type; // 価格 private int price; } @Test public void test() { // 商品一覧 Item item1 = new Item("N1", "T1", 1000); Item item2 = new Item("N2", "T1", 2000); Item item3 = new Item("N3", "T1", 3000); Item item4 = new Item("N4", "T2", 4000); Item item5 = new Item("N5", "T2", 5000); Item item6 = new Item("N6", "T2", 6000); Item item7 = new Item("N7", "T3", 7000); Item item8 = new Item("N8", "T3", 8000); Item item9 = new Item("N9", "T3", 9000); List<Item> items = Arrays.asList(item1, item2, item3, item4, item5, item6, item7, item8, item9); System.out.println("items=" + items); // 商品タイプごとに最大価格の商品を抽出 Map<String, Optional<Item>> groupedItems = items.stream() .collect(Collectors.groupingBy(Item::getType, Collectors.maxBy(Comparator.comparingInt(Item::getPrice)))); System.out.println("groupedItems=" + groupedItems); // 価格の降順でソート List<Item> sortedItems = groupedItems.values().stream() .map(Optional::get) .sorted(Comparator.comparing(Item::getPrice).reversed()) .collect(Collectors.toList()); System.out.println("sortedItems=" + sortedItems); // 結果検証 assertThat(sortedItems, contains(item9, item6, item3)); } }
コンソール ※見やすいように改行してる
items=[ SingleSortTest.Item(name=N1, type=T1, price=1000), SingleSortTest.Item(name=N2, type=T1, price=2000), SingleSortTest.Item(name=N3, type=T1, price=3000), SingleSortTest.Item(name=N4, type=T2, price=4000), SingleSortTest.Item(name=N5, type=T2, price=5000), SingleSortTest.Item(name=N6, type=T2, price=6000), SingleSortTest.Item(name=N7, type=T3, price=7000), SingleSortTest.Item(name=N8, type=T3, price=8000), SingleSortTest.Item(name=N9, type=T3, price=9000)] groupedItems={ T1=Optional[SingleSortTest.Item(name=N3, type=T1, price=3000)], T2=Optional[SingleSortTest.Item(name=N6, type=T2, price=6000)], T3=Optional[SingleSortTest.Item(name=N9, type=T3, price=9000)]} sortedItems=[ SingleSortTest.Item(name=N9, type=T3, price=9000), SingleSortTest.Item(name=N6, type=T2, price=6000), SingleSortTest.Item(name=N3, type=T1, price=3000)]
複数ソートの場合
- 価格と数量の降順でソートする
- 商品タイプごとにソート順が1位の商品に絞る
【インプット】
商品名 | 商品タイプ | 価格 | 数量 |
---|---|---|---|
N1 | T1 | 1000 | 1 |
N2 | T1 | 2000 | 1 |
N3 | T1 | 3000 | 1 |
N4 | T2 | 3000 | 2 |
N5 | T2 | 3000 | 3 |
N6 | T2 | 3000 | 4 |
N7 | T3 | 3000 | 1 |
N8 | T3 | 4000 | 1 |
N9 | T3 | 5000 | 1 |
【アウトプット】
商品名 | 商品タイプ | 価格 | 数量 |
---|---|---|---|
N9 | T3 | 5000 | 1 |
N6 | T2 | 3000 | 4 |
N3 | T1 | 3000 | 1 |
【やり方】
- 価格と数量の降順でソートする
- ソート順で商品タイプ一覧を抽出する
- 商品タイプごとに先頭(ソート順が1位)の商品を抽出する
※複数ソートの場合、groupingBy()とmaxBy()だと上手くいかない
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.ToString; import org.junit.Test; import java.util.Arrays; import java.util.Comparator; import java.util.List; import java.util.Optional; import java.util.stream.Collectors; import static org.hamcrest.MatcherAssert.assertThat; import static org.hamcrest.Matchers.contains; public class MultipleSortTest { // 商品 @Getter @ToString @AllArgsConstructor public class Item { // 商品名 private String name; // 商品タイプ private String type; // 価格 private int price; // 数量 private int quantity; } @Test public void test() { // 商品一覧 Item item1 = new Item("N1", "T1", 1000, 1); Item item2 = new Item("N2", "T1", 2000, 1); Item item3 = new Item("N3", "T1", 3000, 1); Item item4 = new Item("N4", "T2", 3000, 2); Item item5 = new Item("N5", "T2", 3000, 3); Item item6 = new Item("N6", "T2", 3000, 4); Item item7 = new Item("N7", "T3", 3000, 1); Item item8 = new Item("N8", "T3", 4000, 1); Item item9 = new Item("N9", "T3", 5000, 1); List<Item> items = Arrays.asList(item1, item2, item3, item4, item5, item6, item7, item8, item9); System.out.println("items=" + items); // 価格と数量の降順でソート List<Item> sortedItems = items.stream() .sorted(Comparator.comparing(Item::getPrice).reversed() .thenComparing(Comparator.comparing(Item::getQuantity).reversed())) .collect(Collectors.toList()); System.out.println("sortedItems=" + sortedItems); // 商品タイプを抽出 List<String> types = sortedItems.stream() .map(Item::getType) .distinct() .collect(Collectors.toList()); System.out.println("types=" + types); // 商品タイプごとに先頭の商品を抽出 List<Item> groupedSortedItems = types.stream() .map(type -> sortedItems.stream() .filter(item -> item.getType().equals(type)) .findFirst()) .map(Optional::get) .collect(Collectors.toList()); System.out.println("groupedSortedItems=" + groupedSortedItems); // 結果検証 assertThat(groupedSortedItems, contains(item9, item6, item3)); } }
コンソール ※見やすいように改行してる
items=[ MultipleSortTest.Item(name=N1, type=T1, price=1000, quantity=1), MultipleSortTest.Item(name=N2, type=T1, price=2000, quantity=1), MultipleSortTest.Item(name=N3, type=T1, price=3000, quantity=1), MultipleSortTest.Item(name=N4, type=T2, price=3000, quantity=2), MultipleSortTest.Item(name=N5, type=T2, price=3000, quantity=3), MultipleSortTest.Item(name=N6, type=T2, price=3000, quantity=4), MultipleSortTest.Item(name=N7, type=T3, price=3000, quantity=1), MultipleSortTest.Item(name=N8, type=T3, price=4000, quantity=1), MultipleSortTest.Item(name=N9, type=T3, price=5000, quantity=1)] sortedItems=[ MultipleSortTest.Item(name=N9, type=T3, price=5000, quantity=1), MultipleSortTest.Item(name=N8, type=T3, price=4000, quantity=1), MultipleSortTest.Item(name=N6, type=T2, price=3000, quantity=4), MultipleSortTest.Item(name=N5, type=T2, price=3000, quantity=3), MultipleSortTest.Item(name=N4, type=T2, price=3000, quantity=2), MultipleSortTest.Item(name=N3, type=T1, price=3000, quantity=1), MultipleSortTest.Item(name=N7, type=T3, price=3000, quantity=1), MultipleSortTest.Item(name=N2, type=T1, price=2000, quantity=1), MultipleSortTest.Item(name=N1, type=T1, price=1000, quantity=1)] types=[T3, T2, T1] groupedSortedItems=[ MultipleSortTest.Item(name=N9, type=T3, price=5000, quantity=1), MultipleSortTest.Item(name=N6, type=T2, price=3000, quantity=4), MultipleSortTest.Item(name=N3, type=T1, price=3000, quantity=1)]