web-dev-qa-db-ja.com

日付によるアイテムのグループ化

リストにアイテムがあり、アイテムの作成日を示すフィールドがあります。

enter image description here

そして、ユーザーが与える「圧縮」に基づいてそれらをグループ化する必要があります。オプションはDayWeekMonthおよび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 =年

この問題の最善の解決策は何でしょうか?私はそれを開始することさえできなかった、そして私は反復以外の解決策を考えることができない。

12
drJava

私は分類子で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))));
_

LocalDateLocalDate.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日とグループ化します。

3

このような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>());
2
Joey Pinto

私がもっと注意を払うべき唯一の詳細は、週の定義です。私はあなたの週が日曜日に始まり、それが第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)));
}
2
user7605325

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でグループ化する

1
azro