Ich versuche, das Optimalste herauszufinden und mit einer minimalen Anzahl von Schleifen mein Array von js-Datumsobjekten daraus zu gruppieren: (Beachten Sie, dass dies die Ausgabe der Browserkonsole ist, es sind tatsächlich echte JS-Datumsangaben wie new Date ())

[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)]

Zu einem oragnierten Array mit jedem Datum desselben Tages in einem "Block", damit ich es auf der Benutzeroberfläche "Aug 08" anzeigen und 2 oder wie viele Daten innerhalb dieses Tages anzeigen kann.

Beispielsweise:

[{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)]}]

Meine derzeitige Art, darüber nachzudenken, war

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

Danach erhalten Sie einzigartige Tage:

_.uniq(startDays, true)

Und nachdem ich die einzigartigen Tage erhalten habe, kann ich dieser Gruppe eine weitere Schleife hinzufügen, um den gleichen Tag hinzuzufügen, wie Sie jetzt sehen können. Vielleicht sehen Sie, warum ich es nicht mag, und deshalb würde ich gerne eine kluge Hilfe bekommen, weil nichts zu meiner kommt Kopf damit. Dankeschön.

30
Mark 8 Aug. 2015 im 08:44

4 Antworten

Beste Antwort

Unterstrich hat die Funktion _.groupBy , die genau das tun sollte, was Sie wollen:

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

Dadurch wird ein Objekt zurückgegeben, bei dem jeder Schlüssel ein Tag ist, und der Wert ein Array, das alle Vorkommen für diesen Tag enthält.

Um das Objekt in ein Array mit der gleichen Form wie in der Frage umzuwandeln, können Sie map verwenden:

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

Zum Gruppieren, Zuordnen und Sortieren können Sie Folgendes tun:

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();
56
Gruff Bunny 8 Aug. 2015 im 10:25

Warum brauchen Sie diese Optimierung? Wenn Ihr Array nicht groß genug ist, müssen Sie Ihren Algorithmus wahrscheinlich nicht optimieren.

Ich bin mit den angegebenen js-Bibliotheken nicht vertraut, aber Sie können Ihr Array mit einer Schleife nach Tagen gruppieren. Sie müssen jedoch irgendwie den aktuellen Tag im Array bestimmen und dann das entsprechende js-Objekt mit einem Tagesfeld und einem Zeitfeld erstellen und dieses Objekt dann zu Ihrem resultierenden Array hinzufügen. Es ist viel schneller, wenn Sie Ihr Array vor der Implementierung dieses Algorithmus vorsortieren.

-4
SergeyAn 8 Aug. 2015 im 06:26

Wenn Sie auch nach Jahr oder (und) Monat mit Tag gruppieren müssen, empfehle ich, meine Lösung zu verwenden.

Wenn Sie in den obigen Antworten unterschiedliche Monate oder Jahre mit demselben Tag erhalten, ist Ihre Gruppierung falsch.

Schauen Sie sich die gute Lösung an:

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

Was mache ich hier Erstellen Sie einfach einen eindeutigen Schlüssel für jedes Datum, der Folgendes umfasst: Jahr, Monat und Tag. Und dann gruppiere ich ein Array nach diesem eindeutigen Schlüssel.

Ergebnis

0
Niklavr 28 Juni 2017 im 20:40

Angenommen, Ihre Daten sind tatsächlich Zeichenfolgen, ich weiß nicht, warum Sie glauben, eine dieser Bibliotheken zu benötigen. Sie gruppieren nur Zeichenfolgen basierend auf Teilzeichenfolgen.

ES5 führte , was großartig ist, um Dinge anzusammeln:

Ein Helfer zum Erstellen einer Reihe von Daten:

// 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;
}

Diese Antwort befasste sich ursprünglich mit Zeichenfolgen, die für die Verwendung mit Datumsangaben geändert wurden:

// 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));

Wenn optimale Leistung der Schlüssel ist, ist die oben genannte 20-mal schneller als die Unterstrich + Moment-Lösung für ein Array von 5 bis 100 Daten. Um es schneller zu machen, entfernen Sie alle Iteratoren und Bibliotheken und verwenden Sie eine einzige Funktion mit for-Schleifen. Beachten Sie, dass die obige Codezeile nur eine Codezeile länger ist als die Lösung mit Moment.js und underscore.js.

12
RobG 8 Aug. 2015 im 23:41