web-dev-qa-db-fra.com

Tableau de dates JS Comment grouper par jours

J'essaie de trouver le moyen le plus optimal et avec le moins de boucles possible pour grouper mon tableau d'objets js dates à partir de ceci: (Notez que ceci est une sortie de la console du navigateur.

[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sun Aug 09 2015 09:30:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Mon Aug 10 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Tue Aug 11 2015 23:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 18:00:00 GMT+0200 (Central Europe Daylight Time), Wed Aug 12 2015 23:00:00 GMT+0200 (Central Europe Daylight Time)]

à un tableau oragné avec chaque date du même jour dans un "morceau" afin que je puisse l'afficher sur l'interface utilisateur "Août 08" et afficher 2 ou combien de dates à l'intérieur de ce jour.

par exemple:

[{day: 'Aug 08', times:[Sat Aug 08 2015 08:30:00 GMT+0200 (Central Europe Daylight Time), Sat Aug 08 2015 09:30:00 GMT+0200 (Central Europe Daylight Time)]}]

Ma façon actuelle, je pensais le faire était 

var startDays = _.map(occurences, function (date) {
  return moment(date).startOf('day').format();
});

Après cela, pour obtenir des jours uniques:

_.uniq(startDays, true)

et après avoir eu les jours uniques, une autre boucle à ajouter le même jour à ce groupe, comme vous pouvez le voir, vous comprendrez peut-être pourquoi je ne l’aime pas et c’est la raison pour laquelle j’aimerais obtenir une aide intelligente, la tête avec ça. Je vous remercie.

14
Mark

Underscore a la fonction _.groupBy qui devrait faire exactement ce que vous voulez:

var groups = _.groupBy(occurences, function (date) {
  return moment(date).startOf('day').format();
});

Cela retournera un objet où chaque clé est un jour et la valeur un tableau contenant toutes les occurrences de ce jour.

Pour transformer l'objet en un tableau de même forme que dans la question, vous pouvez utiliser map:

var result = _.map(groups, function(group, day){
    return {
        day: day,
        times: group
    }
});

Pour grouper, cartographier et trier, vous pouvez faire quelque chose comme:

var occurrenceDay = function(occurrence){
    return moment(occurrence).startOf('day').format();
};

var groupToDay = function(group, day){
    return {
        day: day,
        times: group
    }
};

var result = _.chain(occurences)
    .groupBy(occurrenceDay)
    .map(groupToDay)
    .sortBy('day')
    .value();
41
Gruff Bunny

En supposant que vos données sont en fait des chaînes, je ne sais pas pourquoi vous pensez avoir besoin de l'une ou l'autre de ces bibliothèques. Vous ne faites que regrouper des chaînes en fonction de sous-chaînes.

ES5 a introduit réduire , ce qui est excellent pour accumuler des objets:

Un assistant pour créer un tableau de dates:

// Generate a dates array given a start date and how many to create:
function genDates(startDate, count) {
  var d = new Date(+startDate),
      dates = [d];
  for (var i=0; i<count; i++) {
    d = new Date(+d);
    d.setHours(d.getHours() + 10);
    dates.Push(d);
  }
  return dates;
}

Cette réponse traitait à l'origine des chaînes, modifiées pour fonctionner avec Dates:

// Generate date key 'MMM dd'
// Replaces use of moment.js
function getDateKey(date) {
  var d = date.getDate();
  var m = ['Jan','Feb','Mar','Apr','May','Jun','Jul','Aug','Sep','Oct','Nov','Dec'];
  return m[date.getMonth()] + ' ' + ((d<10?'0':'') + d);
}

// Generate an array in format [{day:'MMM dd', times:[d0, d1, ...]}, ...]
// Replaces use of underscore.js
var obj = dates.reduce(function(acc, d) {
            var p = getDateKey(d)
            if (!acc[0].hasOwnProperty(p)) acc[0][p] = [];
            acc[0][p].Push(d);
            return acc;
          },[{}])
          .reduce(function(acc, v){
            Object.keys(v).forEach(function(k){acc.Push({day:k, times:v[k]})});
            return acc;
          },[]);

console.log(JSON.stringify(obj));

Si la performance optimale est la clé, la solution ci-dessus est 20 fois plus rapide que la solution de soulignement + Moment pour un tableau de 5 à 100 dates. Pour accélérer le processus, supprimez toute utilisation d'itérateurs et de bibliothèques et utilisez une seule fonction avec des boucles for. Notez que ce qui précède ne représente qu'une ligne de code plus longue que la solution utilisant Moment.js et underscore.js.

10
RobG

Si vous devez également regrouper par année ou (et) mois avec jour, je vous recommande d’utiliser ma solution.

Dans les réponses ci-dessus, si vous obtenez un mois ou une année différent le même jour, votre regroupement sera incorrect. 

Regardez la bonne solution:

_.groupBy(arrayOfDates, function (el) {
      return (el.getFullYear() + '|y|') + (el.getMonth() + '|m|') + (el.getDate() + '|d|');
    });

Qu'est-ce que je fais ici? Créez simplement une clé unique pour chaque date, qui comprend: année, mois et jour. Et puis je groupe un tableau par cette clé unique. 

résultat

0
Niklavr