2015-05-15 4 views
8

Ho bisogno di raggruppare i miei dati per ogni minuto del giorno e ottenere il conteggio degli eventi che si sono verificati durante quel minuto. Al momento ho:C# ottiene il numero minuto dalla data nel gruppo linq di

   items.GroupBy(x => new 
       { 
        x.date.Minute, 
        x.date.Hour 
       }) 
       .Select(x => new TransferObject 
       { 
        Minute = x.Key.Minute, 
        Hour = x.Key.Hour, 
        Count = x.Count(), 
        Day = date 
       }).OrderBy(x => x.Hour).ThenBy(x => x.Minute).ToList(); 

Questo non fa quello che mi serve, ma il problema è che non può avere punti di dati per ogni minuto, come potrei aggiungere 0 a Count campo se non ho i dati per quel minuto ? In alternativa, potrei aggiungere il numero minuto (0 ... 1440) e aggiungere i valori mancanti in seguito.

EDIT

La soluzione attualmente gruppi da solo la data di partenza, ma che in realtà oggetto ha un campo end_date. Quindi, in pratica, al momento ho tutti gli eventi che sono iniziati in quel minuto, ma ho bisogno di ottenere il conteggio degli eventi che erano in esecuzione in quel minuto.

I dati che ho contiene:

date     end_date 
2015-05-15 09:52:15.650 2015-05-15 09:55:38.097 
2015-05-15 09:52:15.633 2015-05-15 09:52:16.097 
2015-05-15 09:52:11.633 2015-05-15 09:52:13.047 
2015-05-15 09:51:49.097 2015-05-15 09:55:17.687 
2015-05-15 09:51:49.087 2015-05-15 09:56:17.510 

Al momento la non utilizza il campo end_date quindi l'uscita è

{Count:2;Hour:9;Minute:51} 
{Count:3;Hour:9;Minute:52} 

ho bisogno di avere tutti gli eventi che erano in esecuzione, qualcosa come

{Count:2;Hour:9;Minute:51} 
{Count:5;Hour:9;Minute:52} 
{Count:3;Hour:9;Minute:53} 
{Count:3;Hour:9;Minute:54} 
{Count:3;Hour:9;Minute:55} 
{Count:2;Hour:9;Minute:56} 
+0

veda la risposta aggiornata. – Jamiec

risposta

1

In primo luogo si potrebbe generare tutte le ore & minuti in un giorno utilizzando alcuni semplici LINQ:

var all = Enumerable.Range(0,24) 
        .SelectMany(x => Enumerable.Range(0,60), 
           (x,y) => new {Hr = x, Min=y}); 
foreach(var a in all) 
    Console.WriteLine("{0}:{1}",a.Hr,a.Min); // 00:00 thru 23:59 

vivo esempio: http://rextester.com/NPNKN82691

È quindi possibile utilizzare questa raccolta per unirsi ai suoi risultati originali per formare l'output finale:

var all = Enumerable.Range(0,24) 
        .SelectMany(x => Enumerable.Range(0,60), 
           (x,y) => new {Hr = x, Min=y}); 

var items = new[]{ 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,3,0)} 
}; 

var results = all.GroupJoin(items, 
          x => new {Hour = x.Hr,Minute = x.Min}, 
          y => new {Hour = y.Date.Hour,Minute = y.Date.Minute}, 
          (x,y) => new {Hour = x.Hr, Minute = x.Min, Count = y.Count()}); 

foreach(var result in results) 
    Console.WriteLine("{0:00}:{1:00} = {2}",result.Hour, result.Minute, result.Count); 

uscita

00:00 = 0
00:01 = 6
00:02 = 0
00:03 = 1
00:04 = 0
//..snip ..//
23:55 = 0
23:56 = 0
23:57 = 0
23:58 = 0
23:59 = 0

esempio vivo http://rextester.com/OAYZ95244


EDIT

Data la tua chan ge di esigenza di prendere in considerazione una gamma date , è possibile aggiungere una nuova classe e il metodo utilizzato per estrapolare minuto ora & da ogni voce:

// classes used 
public class ExtrapolatedItem 
{ 
    public int Hour{get;set;} 
    public int Minute{get;set;} 
} 

public class Item{ 
    public DateTime Date{get;set;} 
    public DateTime EndDate{get;set;} 
} 

// method 

private static IEnumerable<ExtrapolatedItem> Extrapolate(Item item) 
{ 
    for(var d = item.Date;d<=item.EndDate; d = d.AddMinutes(1)) 
    { 
     yield return new ExtrapolatedItem{ Hour = d.Hour, Minute = d.Minute}; 
    } 
} 

Questo può quindi essere utilizzato nel metodo originale in questo modo:

var items = new[]{ 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,1,0),EndDate = new DateTime(2015,1,1,0,5,0)}, 
     new Item{Date = new DateTime(2015,01,01,0,3,0),EndDate = new DateTime(2015,1,1,0,5,0)} 
}; 
var results = all.GroupJoin(items.SelectMany(Extrapolate), // extrapolate each item to a list of extrapolated items 
          x => new {Hour = x.Hr,Minute = x.Min}, 
          y => new {Hour = y.Hour,Minute = y.Minute}, 
          (x,y) => new {Hour = x.Hr, Minute = x.Min, Count = y.Count()}); 

uscita

00:00 = 0
00:01 = 6
00:02 = 6
00:03 = 7
00:04 = 7
00:05 = 7
00:06 = 0
00:07 = 0
//..snip. .//

esempio dal vivo: http://rextester.com/VOVJCS56741

4

Sembra che vogliate GroupJoin() non solo GroupBy(), qualcosa di simile:

var source = ... // Your query; 

    var result = Enumerable 
    .Range(0, 1440) // All the minutes that should be in the result 
    .GroupJoin(source, 
     minutes => minutes, 
     item => item.Hour * 60 + item.Minute, 
     (minutes, items) => new { 
      hour = minutes/60, 
      minute = minutes % 60, 
      count = items.Count() }); // Count() can well return 0... 
0

Questo dovrebbe funzionare senza alcun join. Assumi solo una singola data negli articoli.

var date = items.Select(i => i.date).Min(); 

Enumerable.Range(0, 60 * 24) 
.Select(i => 
    new 
    { 
     Minute = i % 60, 
     Hour = i/60, 
     Day = date, 
     Count = items.Where(j => j.date.Hour = i/60 && j.date.Minute = i % 60).Count() 
    }); 
+0

Questo sarà molto inefficiente; enumerando efficacemente l'insieme di 'items' per ogni minuto in un giorno (1440 volte). Se 'items' è piccolo, probabilmente non è un problema ma se è grande - eek! – Jamiec