public Statistic GetStatistic(StatisticFunc statisticFunc, Filter filter) { if (filter.GroupingPeriod == null) { filter.GroupingPeriod = "date"; } if (filter.Per == null) { filter.Per = "none"; } var senders = messageService.GetAllSenders(); var statistic = Get(statisticFunc, senders, filter.FromDate, filter.ToDate, filter.GroupingPeriod); if (filter.Per != "none") { Statistic perStatistic; switch (filter.Per) { case "message": perStatistic = this.Get(statisticFuncsService.TotalNumberOfMessages(), senders, filter.FromDate, filter.ToDate, filter.GroupingPeriod); break; case "word": perStatistic = this.Get(statisticFuncsService.TotalNumberOfWords(), senders, filter.FromDate, filter.ToDate, filter.GroupingPeriod); break; case "character": perStatistic = this.Get(statisticFuncsService.TotalNumberOfCharacters(), senders, filter.FromDate, filter.ToDate, filter.GroupingPeriod); break; default: throw new ArgumentOutOfRangeException("Per cannot be: " + filter.Per); } Func <float, float, float> calculatePer; if (filter.PerReciprocal) { calculatePer = (f, s) => f == 0 ? 0 : s / f; } else { calculatePer = (f, s) => s == 0 ? 0 : f / s; } statistic.Total = calculatePer(statistic.Total, perStatistic.Total); foreach (var senderId in statistic.TotalBySenders.Keys) { if (perStatistic.TotalBySenders.TryGetValue(senderId, out float value)) { statistic.TotalBySenders[senderId] = calculatePer(statistic.TotalBySenders[senderId], value); } else { statistic.TotalBySenders[senderId] = 0; } } for (int i = 0; i < statistic.TimePeriods.Count; i++) { var j = perStatistic.TimePeriods.IndexOf(statistic.TimePeriods[i]); if (j == -1) { foreach (var senderId in statistic.ValuesBySendersOnTimePeriods.Keys) { statistic.ValuesBySendersOnTimePeriods[senderId][i] = 0; } statistic.TotalsOnTimePeriods[i] = 0; } else { foreach (var senderId in statistic.ValuesBySendersOnTimePeriods.Keys) { if (perStatistic.ValuesBySendersOnTimePeriods.TryGetValue(senderId, out List <float> forPeriods)) { var value = forPeriods[j]; statistic.ValuesBySendersOnTimePeriods[senderId][i] = calculatePer(statistic.ValuesBySendersOnTimePeriods[senderId][i], value); } else { statistic.ValuesBySendersOnTimePeriods[senderId][i] = 0; } } statistic.TotalsOnTimePeriods[i] = calculatePer(statistic.TotalsOnTimePeriods[i], perStatistic.TotalsOnTimePeriods[j]); } } } statistic.Filter.GroupingPeriod = filter.GroupingPeriod; return(statistic); }
public List <StatisticCacheDTO> GetStatisticCaches(StatisticFunc statisticFunc, DateTime?from, DateTime?to) { var allMessages = messageService.GetAllMessages().OrderBy(o => o.NormalizedSentDate).Decompile(); DateTime firstMessageDate; DateTime lastMessageDate; if (from != null) { var firstMessage = allMessages.FirstOrDefault(o => o.NormalizedSentDate >= from.Value); if (firstMessage == null) { return(new List <StatisticCacheDTO>()); } firstMessageDate = firstMessage.NormalizedSentDate; } else { firstMessageDate = allMessages.FirstOrDefault().NormalizedSentDate; } if (to != null) { var lastMessage = allMessages.LastOrDefault(o => o.NormalizedSentDate <= to.Value); if (lastMessage == null) { return(new List <StatisticCacheDTO>()); } lastMessageDate = lastMessage.NormalizedSentDate; } else { lastMessageDate = allMessages.LastOrDefault().NormalizedSentDate; } if (firstMessageDate > lastMessageDate) { return(new List <StatisticCacheDTO>()); } var caches = mainDbContext.StatisticCaches .Include(o => o.ForSenders) .Where(o => o.StatisticName == statisticFunc.Name) .Where(o => o.ForDate >= firstMessageDate && o.ForDate <= lastMessageDate).ToList(); var senders = messageService.GetAllSenders(); var days = Math.Round((lastMessageDate - firstMessageDate).TotalDays) + 1; if (caches.Count < days) { var messages = messageService.GetAllMessages().FilterDateRange(firstMessageDate, lastMessageDate).ToList(); for (int i = 0; i < days; i++) { var date = firstMessageDate.AddDays(i); if (caches.Find(o => o.ForDate == date) == null) { var newCache = new StatisticCache() { StatisticName = statisticFunc.Name, ForDate = date, ForSenders = senders.Select(sender => new StatisticCacheForSender() { SenderId = sender.Id, Total = statisticFunc.Func(messages.AsQueryable().Filter(sender, date)) }).ToList() }; mainDbContext.StatisticCaches.Add(newCache); caches.Add(newCache); } } mainDbContext.SaveChanges(); } var result = caches.Select(o => new StatisticCacheDTO() { Id = o.Id, ForDate = o.ForDate, StatisticName = o.StatisticName, TotalsForSenders = senders.ToDictionary(s => s.Id, s => { var forSender = o.ForSenders.FirstOrDefault(f => f.Sender == s); if (forSender != null) { return(forSender.Total); } else { return(0); } }) }).ToList(); return(result); }
private Statistic Get(StatisticFunc statisticFunc, List <Sender> senders, DateTime?fromDate, DateTime?toDate, string groupingPeriod) { List <DateTime> timePeriods; Dictionary <int, List <float> > valuesBySendersOnTimePeriods; if (groupingPeriod == "timeOfDay" || groupingPeriod == "hour") { var filteredMessages = messageService.GetAllMessages().FilterDateRange(fromDate, toDate).ToList(); Func <Message, DateTime> groupingSelector = null; switch (groupingPeriod) { case "timeOfDay": groupingSelector = o => new DateTime(2021, 1, 1, o.SentDateTime.Hour, 0, 0); break; case "hour": groupingSelector = o => new DateTime(o.SentDateTime.Year, o.SentDateTime.Month, o.SentDateTime.Day, o.SentDateTime.Hour, 0, 0); break; default: throw new ArgumentOutOfRangeException("Grouping period cannot be: " + groupingPeriod); } var tp = timePeriods = filteredMessages.GroupBy(groupingSelector).Distinct().Select(o => o.Key).OrderBy(o => o).ToList(); valuesBySendersOnTimePeriods = senders .ToDictionary(o => o.Id, o => tp .Select(p => filteredMessages .AsQueryable() .Filter(o) .Where(o => groupingSelector(o) == p)) .AsParallel() .AsOrdered() .Select(i => (float)statisticFunc.Func(i)) .ToList()); } else { var caches = statisticCacheService.GetStatisticCaches(statisticFunc, fromDate, toDate); Func <StatisticCacheDTO, DateTime> groupingSelector = null; switch (groupingPeriod) { case "date": groupingSelector = o => o.ForDate; break; case "week": groupingSelector = o => o.ForDate.AddDays(-(((int)o.ForDate.DayOfWeek + 6) % 7)); break; case "month": groupingSelector = o => new DateTime(o.ForDate.Year, o.ForDate.Month, 1); break; default: throw new ArgumentOutOfRangeException("Grouping period cannot be: " + groupingPeriod); } var tp = timePeriods = caches.AsEnumerable().GroupBy(groupingSelector).Distinct().Select(o => o.Key).OrderBy(o => o).ToList(); valuesBySendersOnTimePeriods = senders .ToDictionary(o => o.Id, s => timePeriods .Select(p => caches .Where(o => groupingSelector(o) == p) .Sum(o => (float)o.TotalsForSenders[s.Id])) .ToList()); } // izbaci sve dane/sate/tjedne/mjesece u kojima ima totalno 0 poruka/rijeci/znakova for (int i = 0; i < timePeriods.Count; i++) { if (valuesBySendersOnTimePeriods.Sum(o => o.Value[i]) == 0) { timePeriods.RemoveAt(i); valuesBySendersOnTimePeriods.ForEach(o => o.Value.RemoveAt(i)); i--; } } var totalBySenders = valuesBySendersOnTimePeriods.ToDictionary(o => o.Key, o => o.Value.Sum()); var total = totalBySenders.Values.Sum(); List <float> totalsOnTimePeriods = new List <float>(); for (int i = 0; i < timePeriods.Count; i++) { totalsOnTimePeriods.Add(valuesBySendersOnTimePeriods.Sum(o => o.Value[i])); } var result = new Statistic() { Total = total, Filter = new Filter() { FromDate = fromDate, ToDate = toDate, GroupingPeriod = groupingPeriod, Per = "none" }, Senders = senders.ToDictionary(s => s.Id, s => SenderDTO.From(s)), TotalBySenders = totalBySenders, TimePeriods = timePeriods, ValuesBySendersOnTimePeriods = valuesBySendersOnTimePeriods, TotalsOnTimePeriods = totalsOnTimePeriods, StatisticName = statisticFunc.Name }; return(result); }