Java trie un tableau de mois en plusieurs tableaux par mois


J'ai un tableau en Java contenant un ensemble de dates aléatoires:

{ 20 Janvier 2015, 12 Février 2015 20 Février 2015 21 Juin 2015, Le 12 Juillet 2015, 28 Juillet 2015 30 Juillet 2015 24 Septembre 2015 Au 31 Décembre 2015 }

Comment diviser ce tableau en plusieurs tableaux par mois?

Je voudrais

{ {20 Janvier 2015}, {12 Février 2015 20 Février 2015}, {21 Juin 2015}, {12 Juillet 2015, 28 Juillet 2015 30 Juillet 2015}, {Septembre 24 2015}, {31 décembre 2015} }

Je pourrais parcourir tout le tableau et vérifier si la prochaine date est toujours dans le même mois, puis l'ajouter au sous-tableau si c'est le cas. Cependant, je me demandais s'il y avait une méthode plus succincte ou efficace.

Modifier:

De plus, je dois trier par année et par mois afin, par exemple, que le 15 janvier 2014 et le 23 janvier 2015 ne soient pas combinés.

Voici une méthode que j'ai trouvée mais elle ne semble pas terriblement efficace:

private void splitListByMonth(){
    ArrayList<ArrayList<Homework>> mainArrayList = new ArrayList<>();
    ArrayList<String> titleList = new ArrayList<>();

    Calendar calendar = Calendar.getInstance();
    SimpleDateFormat dateFormat = new SimpleDateFormat("MMMM yyy");
    for(Homework homework:mList){
        calendar.setTimeInMillis(homework.getDate());
        String monthString = dateFormat.format(calendar.getTime());

        if(titleList.contains(monthString)){
            int index = titleList.indexOf(monthString);
            mainArrayList.get(index).add(homework);
        } else {
            titleList.add(monthString);
            int index = titleList.indexOf(monthString);
            mainArrayList.get(index).add(homework);
        }
    }
    Log.d("Tag",""+titleList);
    Log.d("Tag",""+mainArrayList);
}
Author: Sufian, 2015-09-24

3 answers

Vous êtes sur la bonne voie, mais la stringification de l'année/mois est la voie lente, il suffit de suivre l'année et le mois:

@SuppressWarnings("null")
private static List<List<Date>> splitByMonth(Date ... dates) {
    List<List<Date>> datesByMonth = new ArrayList<>();
    List<Date> monthList = null;
    int currYear = 0, currMonth = -1;
    Calendar cal = Calendar.getInstance();
    for (Date date : dates) {
        cal.setTime(date);
        if (cal.get(Calendar.YEAR) != currYear || cal.get(Calendar.MONTH) != currMonth) {
            monthList = new ArrayList<>();
            datesByMonth.add(monthList);
            currYear = cal.get(Calendar.YEAR);
            currMonth = cal.get(Calendar.MONTH);
        }
        monthList.add(date);
    }
    return datesByMonth;
}

Notez que le paramètre doit être pré-trié. La question + les commentaires étaient un peu flous sur ce point.

Code de test

public static void main(String[] args) throws Exception {
    // Build list of all dates
    String[] txtDates = { "January 20 2015", "February 12 2015", "February 20 2015", "June 21 2015",
            "July 12 2015", "July 28 2015", "July 30 2015", "September 24 2015", "December 31 2015",
            "January 15 2014", "January 15 2015" };
    SimpleDateFormat fmt = new SimpleDateFormat("MMMM d yyyy");
    Date[] allDates = new Date[txtDates.length];
    for (int i = 0; i < txtDates.length; i++)
        allDates[i] = fmt.parse(txtDates[i]);

    // Sort dates, then split them by month
    Arrays.sort(allDates);
    List<List<Date>> datesByMonth = splitByMonth(allDates);

    // Print result
    for (List<Date> dates : datesByMonth) {
        StringBuilder buf = new StringBuilder();
        for (Date date : dates) {
            if (buf.length() != 0)
                buf.append(", ");
            buf.append(fmt.format(date));
        }
        System.out.println(buf);
    }
}

Sortie

January 15 2014
January 15 2015, January 20 2015
February 12 2015, February 20 2015
June 21 2015
July 12 2015, July 28 2015, July 30 2015
September 24 2015
December 31 2015
 2
Author: Andreas, 2015-09-24 16:34:11

Utilisation des collecteurs java 8.groupingBy, il renvoie une carte, puis obtient des valeurs toList.

    List<List<Date>> partitions = dates.stream().collect(Collectors.groupingBy(e -> e.getYear() * 100 + e.getMonth(), TreeMap::new, Collectors.toList())).values().stream().collect(Collectors.toList());
 0
Author: Feiyu Zhou, 2015-09-24 16:23:23

Joda-Temps

Pour Android, vous devriez utiliser la bibliothèque Joda-Time plutôt que l'ancien java.util.Date/.Classes de calendrier qui se sont avérées si gênantes. Notez que certaines éditions alternatives de Joda-Time ont été publiées pour contourner un problème Android avec lenteur initiale.

Joda-Time inclut une classe YearMonth, juste ce dont nous avons besoin pour représenter l'année et le mois comme clé pour suivre les valeurs de date. Joda-Time a aussi une classe LocalDate pour représenter une valeur de date uniquement sans heure ou fuseau horaire.

, Nous définissons un formateur avec le modèle "MMMM dd yyyy" pour analyser les cordes. Notez que nous spécifions un Locale avec English language sur le formateur afin que ce code s'exécute avec succès sur les JVM où les paramètres régionaux par défaut actuels ont une langue autre que l'anglais. Que la langue s'applique lors de l'analyse des noms des mois "Janvier", "Février", etc.

Nous recueillons les valeurs LocalDate en tant que SortedSet ce qui remplit deux objectifs, (a) élimine les doublons et (b) conserve les dates triées. Notre implémentation de SortedSet est une TreeSet. Chaque objet set est affecté à un objet YearMonth. Un TreeMap les pistes qui YearMonth est l'ensemble des dates. Nous utilisons un TreeMap plutôt que HashMap pour garder les clés dans l'ordre trié, comme il implémente SortedMap. Si vous aviez un nombre énorme d'éléments et que le tri par clé n'était pas critique, alors HashMap pourrait être un meilleur choix pour les performances.

String[] input = { "January 20 2015" , "February 12 2015" , "February 20 2015" , "June 21 2015" , "July 12 2015" , "July 28 2015" , "July 30 2015" , "September 24 2015" , "December 31 2015" };
Map<YearMonth , SortedSet<LocalDate>> map = new TreeMap<>();
DateTimeFormatter formatter = DateTimeFormat.forPattern( "MMMM dd yyyy" ).withLocale( Locale.ENGLISH );
for ( String string : input ) {
    LocalDate localDate = formatter.parseLocalDate( string );
    YearMonth yearMonth = new YearMonth( localDate );
    if (  ! map.containsKey( yearMonth ) ) { // If this is the first encounter with such a year-month, make a new entry.
        map.put( yearMonth , new TreeSet<>() );
    }
    map.get( yearMonth ).add( localDate );
}

Vidage sur console.

System.out.println( "input: " + Arrays.toString( input ) );
System.out.println( "map: " + map );

Lors de l'exécution.

Entrée: [20 janvier 2015, 12 février 2015, 20 février 2015, 21 juin 2015, 12 Juillet 2015, 28 Juillet 2015, 30 Juillet 2015, 24 septembre 2015, 31 décembre 2015]

Carte: {2015-01=[2015-01-20], 2015-02=[2015-02-12, 2015-02-20], 2015-06=[2015-06-21], 2015-07=[2015-07-12, 2015-07-28, 2015-07-30], 2015-09=[2015-09-24], 2015-12=[2015-12-31]}

Java.temps

Dans Java 8 et versions ultérieures, vous pouvez utiliser le nouveau java intégré.cadre de temps. Joda-Time a fourni l'inspiration pour ce cadre. Le code serait très similaire dans le cas de cette réponse.

 0
Author: Basil Bourque, 2015-09-25 06:24:17