Add missing dates to list - c#

I have written a solution which basically adds missing date and sets the sales property for that date in my collection to 0 where it's missing like this:
int range = Convert.ToInt32(drange);
var groupedByDate = tr.Union(Enumerable.Range(1, Convert.ToInt32(range))
.Select(offset => new MyClassObject
{
Date = DateTime.Now.AddDays(-(range)).AddDays(offset),
Sales = 0
})).GroupBy(x => x.Date)
.Select(item => new MyClassObject
{
Sales = item.Sum(x => x.Sales),
Date = item.Key
})
.OrderBy(x => x.Date)
.ToList();
The first solution where the dates from DB were grouped by and they were missing looked like this:
var groupedByDate = tr
.GroupBy(x => x.TransactionDate.Date)
.Select(item => new MyClassObject
{
Sales = item.Sum(x => x.QuantityPurchased),
Date = item.Key.ToString("yyyy-MM-dd")
})
.OrderBy(x => x.Date)
.ToList();
I don't really like the way I did it in first solution, the code looks very messy and I honestly believe it can be written in a better manner..
Can someone help me out with this?
P.S. The first solution above that I've shown works just fine, but I would like to write something better which is more prettier to the eyes, and it looks quite messy (the first solution I wrote)...

How about generate the date range and then left join that with the result from your original query. And than set Sales to 0 when there is no match.
int range = 2;
var startDate = DateTime.Now;
var dates = Enumerable.Range(1, range)
.Select(offset => startDate.AddDays(-offset).Date);
var groupedByDate = from date in dates
join tmp in groupedByDate on date equals tmp.Date into g
from gr in g.DefaultIfEmpty()
select new MyClassObject
{
Sales = gr == null ? 0 : gr.Sales,
Date = date
};

Here is the easy way to do this:
var lookup = tr.ToLookup(x => x.TransactionDate.Date, x => x.QuantityPurchased);
var quantity = lookup[new DateTime(2017, 6, 29)].Sum();
If you want a range of dates then it's just this:
var startDate = new DateTime(2017, 6, 1)
var query =
from n in Enumerable.Range(0, 30)
let TransactionDate = startDate.AddDays(n)
select new
{
TransactionDate,
QuantityPurchases = lookup[TransactionDate].Sum(),
};
Simple.

Related

where clause not working in group by LINQ c sharp

I have a table "register_operation with fields"
[Key]
int id_registru_casa ,
DateTime data ,
int id_cont_sintetic ,
decimal suma ,
string tip
tip can take only 2 value :"receipts" and "payments"
"Groupby" work with no problem
but when I add "where" clause not working
(it doesn't show me any records)
(although there are recordings in database with day 19, month 9 and tip=receipts)
var centralizator_rc = db.register_operation
.Where(i => (i.data.Day == 19) && (i.data.Month == 9) && (tip=="receipts"))
.GroupBy(i => i.id_cont_sintetic)
.Select(g => new {
id_cont_sintetic = g.Key,
total_receipts = g.Sum(i=>i.suma),
}).ToList();
Thanks!
SOLVED!
I change code like this:
var centralizator_rc = db.registru_casa
.Where(crc=>(crc.data.Month==8) && (crc.data.Day==16) && (crc.tip=="receipts"))
.GroupBy(crc=> new
{
crc.id_cont_sintetic,
crc.data.Month,
crc.data.Day,
crc.tip
})
.Select(g => new {
data = ziuaOK,
id_cont_sintetic = g.Key.id_cont_sintetic,
total_incasare = g.Sum(i => i.suma),
}).ToList();

Merge two arrays into one and get each item's occurrence in their parent array

I have two arrays of dates. I want to merge them into one array that stores each (distinct) dates and their occurrences in their parent arrays.
For example:
var today = new DateTime (year:2022, month:01, day:01);
var firstDateArray = new DateTime[] { today.AddDays(1), today.AddDays(7), today, today.AddDays(3), today };
var secondDateArray = new DateTime[] { today.AddDays(7), today, today.AddDays(3), today.AddDays(3), today.AddDays(1) };
I want to get something like this as a result.
How do I go about this please?
Here I used a tuple (DateTime, int, int) to represent the data:
List<(DateTime, int, int)> result = firstDateArray.
Concat(secondDateArray).
Distinct().
Select(x => (
x,
firstDateArray.Where(y => y == x).Count(),
secondDateArray.Where(z => z == x).Count()
)).
ToList();
You can use .GroupBy, .Select, and .Join for this:
var today = new DateTime (year:2022, month:01, day:01);
var firstDateArray = new DateTime[] { today.AddDays(1), today.AddDays(7), today, today.AddDays(3), today };
var secondDateArray = new DateTime[] { today.AddDays(7), today, today.AddDays(3), today.AddDays(3), today.AddDays(1) };
var firstGrouped = firstDateArray
.GroupBy(d => d)
.Select(g => new { Date = g.Key, Count = g.Count() });
var secondGrouped = secondDateArray
.GroupBy(d => d)
.Select(g => new { Date = g.Key, Count = g.Count() });
var joined = firstGrouped
.Join(secondGrouped, f => f.Date, s => s.Date, (f, s) => new { Date = f.Date, FirstCount = f.Count, SecondCount = s.Count })
.OrderBy(j => j.Date)
.ToList();
GroupBy basically collects items with a common key (in this case the DateTime) and then lets you iterate through the collections.
Join takes 4 arguments: the second enumerable, the key selector for the first, the key selector for the second (it uses these to facilitate the join), and the result selector to produce the result you want.
Documentation:
GroupBy
Select
Join
OrderBy
ToList
Try it online

Nested LINQ query to select 'previous' value in a list

I have a list of dates. I would like to query the list and return a list of pairs where the first item is a date and the second is the date which occurs just before the first date (in the list).
I know this could easily be achieved by sorting the list and getting the respective dates by index, I am curious how this could be achieved in LINQ.
I've done this in SQL with the following query:
SELECT Date,
(SELECT MAX(Date)
FROM Table AS t2
WHERE t2.Date < t1.Date) AS PrevDate
FROM Table AS t1
It is easy as converting your current query into a LINQ query:
var result = table.Select(x =>
new
{
Date = x.Date,
PrevDate = table.Where(y => y.Date < x.Date)
.Select(y => y.Date)
.Max()
});
List<DateTime> dates = new List<DateTime>()
{
DateTime.Now.AddDays(1),
DateTime.Now.AddDays(7),
DateTime.Now.AddDays(3),
DateTime.Now.AddDays(6),
DateTime.Now.AddDays(5),
DateTime.Now.AddDays(2),
DateTime.Now.AddDays(3),
};
dates = dates.OrderByDescending(x => x).ToList();
var result = dates.Skip(1)
.Select((x, i) => new { Date = dates[i], PreviousDate = x });

LINQ-to-SQL - 'Sum' inside a select new

I have a LINQ-to-SQL query that runs through a table, that I want to select 3 sum's - the sums of 'Rate' and 'AdditionalCharges', so I have something like this:
var sums = from d in dc.Deliveries
where d.TripDate == DateTime.Now
select new
{
Rate = d.Rate,
AdditionalCharges = d.AdditionalCharges
};
However, obviously this returns a new row for every delivery, which means I have to sum them up afterwards - which seems fairly inefficient. Is there an easier way?
I know that this is an old question, but hey, I found it, so hopefully this will help someone else...
You can also do this using Fluent syntax:
var sums = dc.Deliveries
.Where(d => d.TripDate == DateTime.Now)
.GroupBy(d => d.TripDate)
.Select(g =>
new
{
Rate = g.Sum(s => s.Rate),
AdditionalCharges = g.Sum(s => s.AdditionalCharges)
});
Hope this helps someone...
If you use query syntax you can do something like the following
var data = dc.Deliveries.Where(d => d.TripDate == DateTime.Now)
var rateSum = data.Sum(d => d.Rate);
var additionalCharges = data.Sum(d => d.AdditionalCharges);
this is off the top of my head and not tested
Not sure but you can try out the group bye function as below
var sums = from d in dc.Deliveries
where d.TripDate == DateTime.Now
group d by new {d.Rate,d.AdditionalCharges,d.TripDate} into g
select new
{
Rate = g.Sum(s => s.Rate ),
AdditionalCharges = g.Sum(s => s.AdditionalCharges)
};
You should be able to do this:
DateTime d = DateTime.Now;
var sums = from d in dc.Deliveries
select new
{
Rate = dc.Deliveries.Where(n => n.TripDate == d).Sum(n => n.Rate),
AdditionalCharges = dc.Deliveries.Where(n => n.TripDate == d).Sum(n => n.AdditionalCharges)
};
var result = sums.FirstOrDefault();
var sums = from d in dc.Deliveries
where d.TripDate == DateTime.Now
Group by d.TripDate // or primary key
Into TotalRate = sum(d.Rate),
TotalAdditionalCharges = sum(d.AdditionalCharges)
Select TotalRate , TotalAdditionalCharges

linq groupby Months and add any missing months to the grouped data

I have created a linq statement which seems to be working ok. I may or maynot have written it correctly however its returning my expected results.
var grouped = RewardTransctions.GroupBy(t => new
{
t.PurchaseDate.Value.Month
}).Select(g => new TransactionDetail()
{
Month =
g.Where(w=>w.EntryType==1).Select(
(n =>
n.PurchaseDate.Value.Month))
.First(),
TransactionAmount = g.Count()
});
Now the results are returning 5 values grouped by months. Is it possible to add the 7 other missing months with a TransactionAmount = 0 to them?
The reason for my madness is I am trying to bind these values to a chart and having my x axis based on months. Currently its only showing the 5 months of records. If my data doesnt return any value for a month I some how want to add in the 0 value.
Any suggestions?
It's very simple if you use .ToLookup(...).
var lookup =
(from w in RewardTransctions
where w.EntryType == 1
select w).ToLookup(w => w.PurchaseDate.Value.Month);
var grouped =
from m in Enumerable.Range(1, 12)
select new TransactionDetail()
{
Month = m,
TransactionAmount = lookup[m].Count(),
};
How's that for a couple of simple LINQ queries?
When you're using LINQ to Objects, this query should do the trick:
var grouped =
from month in Enumerable.Range(1, 12)
select new TransactionDetail()
{
Month = month,
TransactionAmount = RewardTransactions
.Where(t => t.PurchaseDate.Value.Month == month).Count()
};
When RewardTransactions however is an IQueryable, you should first call AsEnumerable() on it.
Why not do it just like this:
var grouped =
RewardTransctions.GroupBy(t => t.PurchaseDate.Value.Month).Select(
g => new TransactionDetail { Month = g.Key, TransactionAmount = g.Count() }).ToList();
for (var i = 1; i <= 12; ++i)
{
if (grouped.Count(x => x.Month == i) == 0)
{
grouped.Add(new TransactionDetail { Month = i, TransactionAmount = 0 });
}
}
It's not entirely LINQ, but straight forward. I also simplified your LINQ query a bit ;-)
I guess If you do not use an anonymoustype(var), but create a custom type and do a .ToList() on your query that you can use .Add() on your list and bind the chart to the list.

Categories