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);
}
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
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());
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.