Jaki jest algorytm tej karuzelki z Hot Deals?
A tak dokładniej to na główną trafiają komiksy, które w zeszłym dniu miały największy rabat. Jaki rabat? W tej chwili sortuję po rabacie od ceny okładkowej. Niestety widziałem kilka komiksów, w których cena zmieniła się o 0.1% i już kwalifikowały się na główną. Z tego powodu myślę co zrobić, ale chyba zacznę sortować po różnicy od ostatniej ceny.
Na plus: widać większe jednorazowe obniżki.
Na minus: ciężej o rabaty powyżej 40%, będzie sporo 38%.
Albo zrobię obie opcje do wyboru, kod w sumie już w większości gotowy.
W sumie to nie tajemnica, nie jest to profesjonalny kod, ale ile czasu zaoszczędzone, AI wypluło takie spaghetti (wydajność nieistotna, to i tak trafia do cache):
public List<ShopIssuePriceDifferenceDto> IssuePriceHistoryBiggestPriceDifferences(int count, ComparisonMode mode)
{
// STEP 1: Get Latest Dates
var latestDates = _applicationDbContext.IssuePriceHistory
.GroupBy(x => new { x.ShopId, x.IssueId })
.Select(g => new
{
g.Key.ShopId,
g.Key.IssueId,
LatestDate = g.Max(x => x.AddDate)
});
// STEP 2: Prepare History Data (Strictly Typed)
// We define a common structure so the compiler doesn't get lost
var historyData = _applicationDbContext.IssuePriceHistory
.Join(latestDates,
h => new { h.ShopId, h.IssueId },
l => new { l.ShopId, l.IssueId },
(h, l) => new { History = h, Latest = l })
.Where(x => x.History.AddDate < x.Latest.LatestDate)
.GroupBy(x => new { x.History.ShopId, x.History.IssueId })
.Select(g => new
{
g.Key.ShopId,
g.Key.IssueId,
// Optimization: If mode is LastKnown, we need a 2-step process,
// but for a single LINQ chain to compile, we often simplify to one structure.
// Below is the specific fix for the compiler error:
RefPrice = (decimal?)g.Max(x => x.History.Price)
});
// RE-IMPLEMENTING the Logic Split correctly without 'dynamic':
if (mode == ComparisonMode.LastKnownPrice)
{
// 1. Find Previous Date
var previousDates = _applicationDbContext.IssuePriceHistory
.Join(latestDates,
h => new { h.ShopId, h.IssueId },
l => new { l.ShopId, l.IssueId },
(h, l) => new { History = h, Latest = l })
.Where(x => x.History.AddDate < x.Latest.LatestDate && !x.History.Banned && !x.History.Skip && !x.History.Done)
.GroupBy(x => new { x.History.ShopId, x.History.IssueId })
.Select(g => new
{
g.Key.ShopId,
g.Key.IssueId,
PreviousDate = g.Max(x => x.History.AddDate)
});
// 2. Overwrite historyData with specific LastKnown price
// Note: The structure { ShopId, IssueId, RefPrice } MUST match the one above exactly.
historyData = _applicationDbContext.IssuePriceHistory
.Join(previousDates,
h => new { h.ShopId, h.IssueId, h.AddDate },
p => new { p.ShopId, p.IssueId, AddDate = p.PreviousDate },
(h, p) => new
{
h.ShopId,
h.IssueId,
RefPrice = (decimal?)h.Price
});
}
// STEP 3: The Final Join (Now Compiler Safe)
var result = _applicationDbContext.IssuePriceHistory.AsNoTracking()
.Join(latestDates,
current => new { current.ShopId, current.IssueId, current.AddDate },
max => new { max.ShopId, max.IssueId, AddDate = max.LatestDate },
(current, max) => current)
// FIX: The compiler now knows exactly what 'historyData' contains
.Join(historyData,
current => new { current.ShopId, current.IssueId },
hist => new { hist.ShopId, hist.IssueId },
(current, hist) => new
{
current.Id,
current.ShopId,
current.IssueId,
CurrentPrice = current.Price,
ReferencePrice = hist.RefPrice,
current.Done,
current.Banned,
current.Skip,
current.Issue.ISBN13,
current.AddDate,
current.Issue.Price1
})
.Where(x =>
x.CurrentPrice.HasValue &&
x.ReferencePrice.HasValue &&
x.ReferencePrice.Value != 0 &&
// Percent change
(((x.CurrentPrice.Value - x.ReferencePrice.Value) / x.ReferencePrice.Value) * 100) < 0 &&
// Not bigger than -80% (exclude -80%, -90%, etc.)
(((x.CurrentPrice.Value - x.ReferencePrice.Value) / x.ReferencePrice.Value) * 100) >= -80
)
.OrderByDescending(x => x.AddDate.Date)
.OrderByDescending(x =>
Math.Abs(
(x.CurrentPrice.Value - x.ReferencePrice.Value)
/ x.Price1.Value
* 100
)
)
.Take(80000)
.Where(x => !x.Done && !x.Banned && !x.Skip && x.ISBN13.Length > 0)
.Take(count)
.Select(x => new ShopIssuePriceDifferenceDto
{
Id = x.Id,
ShopId = x.ShopId,
IssueId = x.IssueId,
TodayPercent = x.CurrentPrice.Value,
YesterdayPercent = x.ReferencePrice.Value,
AbsoluteDifference = (((x.CurrentPrice.Value - x.ReferencePrice.Value) / x.ReferencePrice.Value) * 100),
Done = x.Done
})
.ToList();
return result;
}
To funkcja, która pobiera z bazy najciekawsze obniżki, lądujące na głównej

.
Edit: Tak sobie myślałem, że największe podwyżki też może ciekawie wyglądać, widać co się wyprzedało :>.