リストにアイテムがあり、アイテムの作成日を示すフィールドがあります。
そして、ユーザーが与える「圧縮」に基づいてそれらをグループ化する必要があります。オプションはDay
、Week
、Month
およびYear
です。
ユーザーがday
圧縮を選択した場合、同じ日に作成されたアイテムがグループ化されるように、アイテムをグループ化する必要があります。上記の例では、アイテム1とアイテム2のみが同じ日に作成されます。他のグループもグループですが、その日に作成されるアイテムは1つだけなので、アイテムは1つだけになります。
{{item1, item2}, {item3}, {item4}, {item5}, {item6}, {item7}}
ユーザーがweek
を選択した場合:
{{item1, item2, item3, item4}, {item5}, {item6}, {item7}}
ユーザーがmonth
を選択した場合:
{{item1, item2, item3, item4, item5}, {item6}, {item7}}
ユーザーがyear
を選択した場合:
{{item1, item2, item3, item4, item5, item6}, {item7}}
グループが作成された後、アイテムの日付は重要ではありません。つまり、グループが作成されている限り、キーは何でもかまいません。
Map
を使用する場合、次のようにキーとして考えました。
day
=年間通算日week
=年間通算週month
=年の月year
=年
この問題の最善の解決策は何でしょうか?私はそれを開始することさえできなかった、そして私は反復以外の解決策を考えることができない。
私は分類子でLocalDate
を調整して_Collectors.groupingBy
_を使用し、同様の日付のアイテムが(compressionに従って)ユーザーによって与えられた)は一緒にグループ化されます。
そのためには、まず次のMap
を作成します。
_static final Map<String, TemporalAdjuster> ADJUSTERS = new HashMap<>();
ADJUSTERS.put("day", TemporalAdjusters.ofDateAdjuster(d -> d)); // identity
ADJUSTERS.put("week", TemporalAdjusters.previousOrSame(DayOfWeek.of(1)));
ADJUSTERS.put("month", TemporalAdjusters.firstDayOfMonth());
ADJUSTERS.put("year", TemporalAdjusters.firstDayOfYear());
_
注:_"day"
_の場合、日付をそのままにするTemporalAdjuster
が使用されます。
次に、ユーザーから提供されたcompression
を使用して、アイテムのリストをグループ化する方法を動的に選択します。
_Map<LocalDate, List<Item>> result = list.stream()
.collect(Collectors.groupingBy(item -> item.getCreationDate()
.with(ADJUSTERS.get(compression))));
_
LocalDate
は LocalDate.with(TemporalAdjuster)
メソッドによって調整されます。
Java 8ストリーム:
Map<LocalDate, List<Data>> byYear = data.stream()
.collect(groupingBy(d -> d.getDate().withMonth(1).withDayOfMonth(1)));
Map<LocalDate, List<Data>> byMonth = data.stream()
.collect(groupingBy(d -> d.getDate().withDayOfMonth(1)));
Map<LocalDate, List<Data>> byWeek = data.stream()
.collect(groupingBy(d -> d.getDate().with(TemporalAdjusters.previousOrSame(DayOfWeek.MONDAY))));
Map<LocalDate, List<Data>> byDay = data.stream()
.collect(groupingBy(d -> d.getDate()));
groupingBy および collect のドキュメント。 4つのケースすべてで、キーとして LocalDate が使用されます。適切にグループ化するために、すべての日付が同じ月日または同じ日を持ち、異なる月または同じ月と同じ曜日(月曜日)を持つように変更されているため、明らかなグループ化規則につながります。データの日付は、キーだけが変更されるわけではありません。これは、年も同じである場合は月が同じであり、完全な日付が同じである場合は日が同じであると見なします。
たとえば、月でグループ化すると、これらの日付は同じキーになります。
2017/01/01->キー01/01/2017
2017/01/01->キー2017/01/01
2017/01/05->キー2017/01/01
週でグループ化すると、これらの日付は同じキーになります(日付は前の月曜日です):
2017年4月1日->キー2017年2月1日
2017年1月5日->キー2017年2月1日
代わりに、たとえば年や月に関係なく、月の同じ日にグループ化することもできます。あなたはこのようにそれを達成するでしょう:
Map<Integer, List<Data>> byDayOfMonth = data.stream()
.collect(groupingBy(d -> d.getDate().getDayOfMonth()));
これは、2017年1月1日を2017年10月1日とグループ化し、2017年5月1日を2018年4月5日とグループ化します。
このようなHashMapを使用してください
<Integer,ArrayList<Date>>
1. set filter=DAY/MONTH/YEAR
2.Iterate the date_obj
3.Use Calendar package to get a variable val=Calendar.get(filter)
4. If hashmap.keyset().contains(val)
hashmap.get(val).add(date_obj.date)
Else
hashmap.put(val,new ArrayList<date_obj>());
私がもっと注意を払うべき唯一の詳細は、週の定義です。私はあなたの週が日曜日に始まり、それが第1週と見なされるために少なくとも1日以上なければならない場合を想定しています。 (ISO 8601では、週は月曜日から始まり、第1週と見なされるには少なくとも4日が必要であると記載されています。日数が少ない場合、第0週と見なされます)。 javadoc で週の定義の詳細を確認できます。
今週の定義を取得するために、私はJava.time.temporal.WeekFields
クラス。明示的にof
メソッドを使用していますが、明示的に最初の曜日と最初の週の最小日数を使用しています(Locale
を使用するバージョンを使用する場合、結果はシステムのデフォルトロケール)。
圧縮タイプの列挙型も作成しましたが、これはオプションです。
enum CompressionType {
DAY, WEEK, MONTH, YEAR;
}
とにかく、日付をグループ化するためにどのフィールドが使用されるかを知るために、圧縮タイプを使用します。次に、Collectors.groupingBy
グループ化を行うには:
// assuming you have a list of dates
List<LocalDate> dates = new ArrayList<>();
dates.add(LocalDate.of(2017, 1, 1));
dates.add(LocalDate.of(2017, 1, 1));
dates.add(LocalDate.of(2017, 1, 4));
dates.add(LocalDate.of(2017, 1, 5));
dates.add(LocalDate.of(2017, 1, 29));
dates.add(LocalDate.of(2017, 10, 1));
dates.add(LocalDate.of(2018, 4, 5));
CompressionType compression = // get CompressionType from user input
final TemporalField groupField;
switch (compression) {
case DAY:
groupField = ChronoField.DAY_OF_YEAR;
break;
case WEEK:
// week starts at Sunday, minimum of 1 day in the first week
groupField = WeekFields.of(DayOfWeek.SUNDAY, 1).weekOfWeekBasedYear();
break;
case MONTH:
groupField = ChronoField.MONTH_OF_YEAR;
break;
case YEAR:
groupField = ChronoField.YEAR;
break;
default:
groupField = null;
}
if (groupField != null) {
Map<Integer, List<LocalDate>> result = dates.stream().collect(Collectors.groupingBy(d -> d.get(groupField)));
}
Item要素に次の属性があると仮定します。
private String item;
private LocalDate date;
あなたはこのようにすることができます:
ArrayList<Element> list = new ArrayList<>();
list.add(new Element("item 1", LocalDate.of(2017, 01, 01)));
list.add(new Element("item 2", LocalDate.of(2017, 01, 01)));
WeekFields weekFields = WeekFields.of(Locale.getDefault());
String userChoice = new Scanner(System.in).nextLine();
Map<Integer, List<Element>> map;
switch (userChoice) {
case "day":
map = list.stream().collect(Collectors.groupingBy(element
-> element.getDate().getDayOfMonth()));
break;
case "week":
map = list.stream().collect(Collectors.groupingBy(element
-> element.getDate().get(weekFields.weekOfWeekBasedYear())));
break;
case "month":
map = list.stream().collect(Collectors.groupingBy(element
-> element.getDate().getMonthValue()));
break;
case "year":
map = list.stream().collect(Collectors.groupingBy(element
-> element.getDate().getYear()));
break;
default:
break;
}
ユーザーの選択に応じて、マップはユーザーの選択に従ってアイテムをマッピングすることになります
詳細:
map = list.stream().collect(Collectors.groupingBy(element
-> element.getDate().getYear()));
これはリストのアイテムを反復処理し、year of the date of the item
でグループ化する