Reputation: 2931
I'm creating system for a company renting apartments. All pricing setup is based on some periods. For example an apartment in category 'Junior Studio' there are price periods:
30.05.2016 - 31.01.2017: 3000 EUR
01.02.2017 - Infinity: 4000 EUR
There are also additional periods like: taxes, seasonal price(plus/minus some percent value), and fees based on other periods. So prices can vary often, for example:
31.05.2016 - 30.06.2016 (3500EUR because of some seasonal price period)
01.07-31.08.2016 (5000EUR other seasonal price period)
01.09.2016 - 31.01.2017 (3000 EUR)
01.02.2017 - 4000 EUR.
Also, if someone wants to rent an apartment, for example less than 15 days, there is additional fee, let's say 15% - all this is set up dynamically.
Now the problem is on our page we should let user find apartments based on their price. For example some users want to find only apartments where the price varies between 3000 - 4000 EUR and rent an apartment for 6 months. As I said price can change for example 5 times on those periods so I'm looking to calculate an average price.
Have you any idea how implement this algorithm to incorporate all the specified periods? We assume there can be for example 500 possible records so computing this dynamically could probably cause performance issues.
UPDATE
Here is some code to take periods related to one apartment category for one building:
private RentPriceAggregatedPeriodsDto prepareRentPriceAggregator(Long buildingId, Long categoryId, LocalDate dateFrom, LocalDate dateTo, Integer duration) {
List<CategoryPricePeriod> pricePeriods = categoryPricePeriodRepository.findCategoryPricePeriods(buildingId, categoryId, dateFrom, dateTo);
List<SeasonalPricePeriod> seasonalPricePeriods = seasonalPricePeriodRepository.findSeasonalPricePeriods(buildingId, categoryId, dateFrom, dateTo);
List<LastMinuteRatePeriod> lastMinuteRatePeriods = lastMinuteRatePeriodRepository.findLastMinuteRatePeriods(buildingId, categoryId, dateFrom, dateTo);
List<TaxesDefinitionPeriodDto> taxesDefinition = taxesDefinitionService.findTaxPeriodsForBuildingAndCategory(buildingId, categoryId, TaxTypeCode.VAT,
dateFrom, dateTo);
Optional<SurchargePolicy> surcharge = surchargePolicyRepository.findForDurationAndRentalObjectCategoryIds(categoryId, buildingId, duration);
return new RentPriceAggregatedPeriodsDto(pricePeriods, seasonalPricePeriods, lastMinuteRatePeriods, taxesDefinition, surcharge);
}
Based on all those periods I prepare list of unique price periods: dateFrom, dateTo, currency, value
. After those steps I have list of unique prices for one category. Then I need to compute how many days of booking is in each of those unique price periods and multiply it, maybe round + multiply by tax and sum it to have final price for booking. Now re-run those steps, let's say, 500 times (multiple categories in multiple buildings).
Upvotes: 0
Views: 159
Reputation: 32542
I think you actually need two algorithms. One for representing and querying the object price at any given time. And another one for computing the price for renting an object for a given time period.
As for the representation of the object price, you should make a decision about the temporal granularity you want to support, e.g., days or months. Then create a lookup table or a decision tree, a neural network or anything to lookup the price at the given day or month for the given object or object class. You can factor in all the variables you'd like to have in there. If you want to support special prices for renting full calendar months, have another data structure for this different granularity, which you query with months instead of dates.
Then, given a period of time, you need to generate the corresponding series of dates or months, query for the individual daily or monthly prices and then compute the sum to get the total price. If you want to, you can then compute an average daily/monthly price.
I don't think performance will be an issue here. At least no issue you should address before coming up with an actual solution (because, premature optimization). If it is, consider scaling up your database.
Upvotes: 1
Reputation: 4343
As mentioned in the comments, averaging 6 numbers 500 times on the fly should not cause any performance issues.
Even then, if you'd want O(1)
performance on computation of price (i.e. the calculation should not depend on the number of price switches in the mentioned period), you could preprocess by defining a date as day 0, and computing the amount of total rent that would be required for all days beyond that. When a user requests the average rent between a period, subtract the total rent till day zero from the two days, giving you the rent for the period in between. Dividing this by the number of days will give you the average rent. You can also add suitable multipliers depending on duration of stay (to add the 15% charge), etc. This is similar to finding the sum of values between two indices in an array in O(1)
. This is not a memory friendly suggestion, although one can modify it to use less memory.
The advantage is that the computation to give results will not depend on the number of price switches. However, every additional change in apartment rents will cause some amount of preprocessing.
Upvotes: 1