How to meet properly if condition - kotlin

I'm having a problem with this task. My goal is to calculate car price providing its mileage.
The formula is:
price lowers by 200$ for every 10000 kilometers that the car passed. For example, for 19999 km the price decreases by 200 dollars, but for 20000 km the price lowers by 400 dollars. And additionally the prices lowers due to car's age multiplied by 200.
What I did is:
when (input) {
in 0..9999 -> {
moneyToRemove = 2000
price -= moneyToRemove
}
else -> {
var counter = 0
moneyToRemove = old * 2000
for (x in 10000..input) {
if (x % 10000 == 0 ) {
counter++
if (x == input) {
println(counter)
price = price - moneyToRemove - counter*200
}
}
}
}
}
input - mileage provided from scanner
In first when condition moneyToRemove variable is set to 2000 ( 5years *200)
In else condition I tried to count how many extra dollars will lower the car price using counter. But then I have a problem with e.g. value 299 999. The counter in debugger mode shows 29 which is correct, but I can't meet the second condition and properly count car's price. Can you help?
This is from JetBrains academy Kotlin dev track.

You don't need any if conditions for that. You can put it in a simple formula
import kotlin.math.*
fun main() {
var originalprice = 30000; // the original price
var miles = 12345.6; // the mileage
var age = 7; //the age in years
var reducedprice = originalprice -
(floor(miles / 10000.0)) * 200 - //substract 200$ for each full 10000 miles
age * 200 //substract 200$ foreach year
print(reducedprice);
}
floor(miles/ 10000.0) will divide the miles by 10000 and round it downwards to the next integer. So it will be 0 for 0-9999, 1 for 10000 - 19999 and so on ... floor
If miles is an integer value, you don't even need floor, because the integer division will only return whole numbers. Ie 9999/10000 = 0, 19999/10000 = 1 and so on ...
var reducedprice = originalprice -
(miles / 10000) * 200 - //substract 200$ for each full 10000 miles
age * 200 //substract 200$ foreach year
EDIT
Eventhough I consider your approach as quite complicated and not easily maintainable
You have code duplication for the age part,
You do a lot of unnecessary % calculations for each value from 10000 up to your input
The when isn't necessary, because all the code exectued in the first branch is also executed in the second branch. Just could just do the loop, starting at 10000, so if the input is < 10000 it won't be executed ...
But all in all, your approach will in principle work too. But there are two issues with it
You don't consider the age of the car, when the mileage is below 10000, but you just withdraw a fixed amount.
When the mileage is above 10000, you calculate the reduced price only if the input is an exact multiple of 10000. You must put that calculation after the loop.
when (input) {
in 0..9999 -> {
moneyToRemove = old * 2000
price -= moneyToRemove
}
else -> {
moneyToRemove = old * 2000
for (x in 10000..input) {
if (x % 10000 == 0 ) {
moneyToRemove += 200
}
}
println(counter)
price -= moneyToRemove
}
}

Related

how to perform dynamic subtraction of a list of numbers with a specific value

My idea is to subtract each value from my list through the value of a variable, for example:
var subtraction = 250
var list = mutableListOf(300, 200, 100)
Then, using the 250 of the subtraction variable,
you can dynamically subtract each value of the item,
from the last to the first, so with that 250 the program should return: -> list(300, 50).
Where 250 is subtracted from item 100 (last item) and then "150" remains from the value "250",
and the remaining 150 is subtracted from 200 (second item) and remains 50,
thus zeroing out the value of "250" and the program stop.
Getting (300, 50) -> 50 which comes from 200 (second item).
As if I was going through my list of numbers, subtracting item by item through the value of a variable, from last to first.
Your question still needs further clarification:
What should be the output if subtraction = 700?
What should be the output if subtraction = 600?
What should be the output if subtraction = 100?
The following can be a starting point to solve your question:
fun subtraction() {
var subtraction = 250
var list = mutableListOf(300, 200, 100)
// Loop the list in Reverse order
for (number in list.indices.reversed()) {
subtraction -= list[number] // Subtract the last number
// If subtraction is greater than zero, continue and remove the last element
if (subtraction > 0)
list.removeAt(number)
else {
// It subtraction is less than or equal to zero,
// remove the last element, append the final subtraction result,
// and stop the loop
list.removeAt(number)
list.add(abs(subtraction))
break
}
}
// If the subtraction result is still positive after whole list has been processed,
// append it back to the list
// if (subtraction > 0)
// list.add(subtraction)
println(list)
}
Output
[300, 50]
The question isn't very clear, but as I understand it: OP wants to modify a list of numbers, subtracting a fixed amount from each, and removing those for which the result would be negative.
If so, it can be done very simply:
list.replaceAll{ it - subtraction }
list.removeIf{ it < 0 }
However, instead of mutating the existing list, it would probably be more common to create a new one:
val newList = list.map{ it - subtraction }.filter{ it >= 0 }
Or, if you need to avoid creating a temporary list:
val newList = list.mapNotNull{ (it - subtraction).takeIf{ it >= 0 } }
A solution with foldRight using a Pair as accumulator:
val list = listOf(300, 200, 100)
val subtraction = 250
val result = list
.foldRight(subtraction to emptyList<Int>()) { item, (diff, list) ->
when {
diff > item -> diff - item to emptyList()
else -> 0 to listOf(item - diff) + list
}
}
.second
println(result) // Output: [300, 50]

BME680 sensor faulty gas reference readings

I have a problem with my BME680 readings. I found example code to collect all the air data and make an air quality score (AIQ) out of that (it goes from 0 to 500). You see in the code bellow that in loop() data is collected and AIQ calculated every 2 seconds, and gas reference is updated/collected on every 5-th reading -> if (getgasreference_count++) % 5 == 0) GetGasReference(); so 5*2 sec= every 10 sec (around 230k ohms).
Problem starts here, where I implement this code in my other program which runs website and controls motors. Here data is collected and AIQ calculated once a minute, gas reference is updated/collected on every 5-th reading -> if (getgasreference_count++) % 5 == 0) GetGasReference(); so 5*60 sec= every 300 sec= 5 min. Thats when I'm getting faulty gas reference readings (around 100k ohms) and of course following calculated AIQ is wrong.
I'm wondering where the problem is because why it matters when you get new gas reference? I'm thinking that bme.setGasHeater(); function has something to do with it, but I don't know how it is related with gas reference readings? I would be grateful if anybody can explain where the problem is.
The working example code is here:
#include <Wire.h>
#include <Adafruit_Sensor.h>
#include <Adafruit_BME680.h>
#define SEALEVELPRESSURE_HPA (1013.25)
#define YOUR_SENSOR_I2C_ADDRESS 0x76
Adafruit_BME680 bme; // I2C
float hum_weighting = 0.25; // so hum effect is 25% of the total air quality score
float gas_weighting = 0.75; // so gas effect is 75% of the total air quality score
int humidity_score, gas_score;
float gas_reference = 2500;
float hum_reference = 40;
int getgasreference_count = 0;
int gas_lower_limit = 10000; // Bad air quality limit
int gas_upper_limit = 300000; // Good air quality limit
void setup() {
Serial.begin(115200);
Serial.println(F("BME680 test"));
Wire.begin();
if (!bme.begin(YOUR_SENSOR_I2C_ADDRESS)) {
Serial.println("Could not find a valid BME680 sensor, check wiring!");
while (1);
} else Serial.println("Found a sensor");
// Set up oversampling and filter initialization
bme.setTemperatureOversampling(BME680_OS_8X);
bme.setHumidityOversampling(BME680_OS_2X);
bme.setPressureOversampling(BME680_OS_4X);
bme.setIIRFilterSize(BME680_FILTER_SIZE_3);
bme.setGasHeater(320, 150); // 320°C for 150 ms
// Now run the sensor to normalise the readings, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage.
// The sensor takes ~30-mins to fully stabilise
GetGasReference();
}
void loop() {
Serial.println("Sensor Readings:");
Serial.println(" Temperature = " + String(bme.readTemperature(), 2) + "°C");
Serial.println(" Pressure = " + String(bme.readPressure() / 100.0F) + " hPa");
Serial.println(" Humidity = " + String(bme.readHumidity(), 1) + "%");
Serial.println(" Gas = " + String(gas_reference) + " ohms\n");
Serial.print("Qualitative Air Quality Index ");
humidity_score = GetHumidityScore();
gas_score = GetGasScore();
//Combine results for the final IAQ index value (0-100% where 100% is good quality air)
float air_quality_score = humidity_score + gas_score;
Serial.println(" comprised of " + String(humidity_score) + "% Humidity and " + String(gas_score) + "% Gas");
if ((getgasreference_count++) % 5 == 0) GetGasReference();
Serial.println(CalculateIAQ(air_quality_score));
Serial.println("--------------------------------------------------------------");
delay(2000);
}
void GetGasReference() {
// Now run the sensor for a burn-in period, then use combination of relative humidity and gas resistance to estimate indoor air quality as a percentage.
//Serial.println("Getting a new gas reference value");
int readings = 10;
for (int i = 1; i <= readings; i++) { // read gas for 10 x 0.150mS = 1.5secs
gas_reference += bme.readGas();
}
gas_reference = gas_reference / readings;
//Serial.println("Gas Reference = "+String(gas_reference,3));
}
String CalculateIAQ(int score) {
String IAQ_text = "air quality is ";
score = (100 - score) * 5;
if (score >= 301) IAQ_text += "Hazardous";
else if (score >= 201 && score <= 300 ) IAQ_text += "Very Unhealthy";
else if (score >= 176 && score <= 200 ) IAQ_text += "Unhealthy";
else if (score >= 151 && score <= 175 ) IAQ_text += "Unhealthy for Sensitive Groups";
else if (score >= 51 && score <= 150 ) IAQ_text += "Moderate";
else if (score >= 00 && score <= 50 ) IAQ_text += "Good";
Serial.print("IAQ Score = " + String(score) + ", ");
return IAQ_text;
}
int GetHumidityScore() { //Calculate humidity contribution to IAQ index
float current_humidity = bme.readHumidity();
if (current_humidity >= 38 && current_humidity <= 42) // Humidity +/-5% around optimum
humidity_score = 0.25 * 100;
else
{ // Humidity is sub-optimal
if (current_humidity < 38)
humidity_score = 0.25 / hum_reference * current_humidity * 100;
else
{
humidity_score = ((-0.25 / (100 - hum_reference) * current_humidity) + 0.416666) * 100;
}
}
return humidity_score;
}
int GetGasScore() {
//Calculate gas contribution to IAQ index
gas_score = (0.75 / (gas_upper_limit - gas_lower_limit) * gas_reference - (gas_lower_limit * (0.75 / (gas_upper_limit - gas_lower_limit)))) * 100.00;
if (gas_score > 75) gas_score = 75; // Sometimes gas readings can go outside of expected scale maximum
if (gas_score < 0) gas_score = 0; // Sometimes gas readings can go outside of expected scale minimum
return gas_score;
}
From this Learn Adafruit page it seems the gas readouts can take up to 30 minutes to stabilize.
Gas is returned as a resistance value in ohms. This value takes up to 30 minutes to stabilize! Once it stabilizes, you can use that as your baseline reading. Higher concentrations of VOC will make the resistance lower.
and on their first page:
We recommend that you run this sensor for 48 hours when you first receive it to "burn it in", and then 30 minutes in the desired mode every time the sensor is in use.

Solo Learn practice how to calculate parking fee based on some conditions in Kotlin

You are making a car parking software that needs to calculate and output the amount due based on the number of hours the car was parked.
The fee is calculated based on the following price structure:
the first 5 hours are billed at $1 per hour.
after that, each hour is billed at $0.5 per hour.
for each 24 hours, there is a flat fee of $15.
This means, that, for example, if a car parked for 26 hours, the bill should be 15+(2*0.5) = 16.0, because it was parked for 24 hours plus 2 additional hours.
Sample Input:
8
Sample Output:
6.5
Explanation: The first 5 hours are billed at $1/hour, which results in $5. After that, the next 3 hours are billed at $0.5/hour = $1.5.
So, the total would be $5+$1.5 = $6.5
Below code works fine however it doesn't satisfy all conditions which are hidden
fun main(args: Array<String>) {
var hours = readLine()!!.toInt()
var total: Double = 0.0
total = when{
hours <= 5 -> {
val cost = hours *1.toDouble()
cost
}
hours in 6..23 -> {
val cost = 5 + (hours - 5) * 0.5
cost
}
hours == 24 -> {
val cost = 15.toDouble ()
cost
}
else -> {
val cost = 15 + (hours -24) * 0.5
cost
}
}
println(total )
}
One case that I think you missed is that, for hours > 24 you always use $15, while as per the question it is $15 per day, so you need to multiply it by the number of days.
Try this code:
fun main(args: Array<String>) {
val hours = readLine()!!.toInt()
val total = when {
hours >= 24 -> 15 * (hours / 24) + 0.5 * (hours % 24)
hours > 5 -> 5 + (hours - 5) * 0.5
else -> hours.toDouble()
}
println(total)
}
Try this code:
fun main (args : Array<String>) {
var hour = readLine()!!.toInt()
var total = when {
hour >= 24 -> (15 * (hour/24)) + (0.5 * (hour%24))
hour > 5 && hour <24 -> 5 + ((hour-5)*0.5)
else -> hour.toDouble()
}
println(total)
}

For loop must have an iterator()

I need this service in which if the person stays for longer than 30 minutes, they have to pay an extra $10 every 15 minutes (and for the fraction of the 15 as well).
I designed it like this so far:
var checkInTime: Calendar
val totalTime: Long
get() = (Calendar.getInstance().timeInMillis - checkInTime.timeInMillis) / MIN_IN_MILISEC
fun getTime(totalTime:Long): Int{
var finalPrice = 0
var initialPrice = 20
if(totalTime<31){
finalFee = initialPrice
} else {
val extraPrice = 10
val extraTime = 15
finalFee = initialPrice
for(extraTime in totalTime){
finalFee += extraTime
}
return finalFee
}
I get the error "For loop must have an iterator()" when I try to loop through the totalTime when it's more than 30 minutes so that I can add $10 every 15 extra minutes. I need some help as to how to add to the finalFee every extra 15 minutes the person stays since my method is not working.
Thank you.
Let's take a look at your getTime function:
You're using a Long as totalTime. You can measure it in minutes to simplify your calculation (since all time values are measured in minutes). Since a Long type in Kotlin stores a integer up to 9,223,372,036,854,775,807 and no soul on Earth will use your service for that long (this represents 17 billion milleniums), you can just use an Int.
You're not declaring the finalFee variable, thus the code will raise an
"Unresolved reference" error. Since you're not using the finalPrice variable, I'm assuming you wanted to use this instead.
You're trying to iterate over a numeric value (in this case, totalTime, which is a Long). You can iterate over each element of a List, but how would you iterate over each element of an integer? I'm assuming you want to do a certain action totalTime number of times. In this case, you would use ranges.
You're also not using the variables extraPrice and extraTime.
There's code that's common to both if-else conditions (finalPrice = initialPrice), so you can extract that to outside the if-statement.
Refactoring your function:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime >= 30) {
(0 until totalTime).forEach {
finalPrice += 15
}
}
return finalPrice
}
It's shorter, but still doesn't do what it's supposed to: let's suppose totalTime is equal to 45. The person got 30 minutes costing $20 and only have to pay $10 for every 15 minutes, therefore will only pay $30 total. Your function is considering that the person will have to pay $15 for every minute they stayed, because it uses a for-loop that goes from 0 to totalTime. For that, you need a for-loop that goes from 30 (the time limit) from the total time (the totalTime) every 15 minutes:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
(30 until totalTime step 15).forEach {
finalPrice += 10
}
}
return finalPrice
}
Better yet, you don't even need a for-loop, you can just use maths:
fun getTime(totalTime: Int): Int {
var finalPrice = 20
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15) * 10
// ^^^^^^^^^^^^^^^^ Get the exceeding time
// ^^^^^^^^^^^^^^^^^^^^^^^ How many 15 minutes are there?
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Put $10 for every 15 minutes
}
return finalPrice
}
The last part: your question said you need to consider the fraction of 15 as well. Therefore, you need to use a real value, not an integer. Let's change it to a Double:
fun getTime(totalTime: Int): Double {
var finalPrice = 20.0
if (totalTime > 30) {
finalPrice += ((totalTime - 30) / 15.0) * 10
}
return finalPrice
}
Let's test your function:
fun main() {
println(getTime(0)) // Outputs 20.0
println(getTime(10)) // Outputs 20.0
println(getTime(30)) // Outputs 20.0
println(getTime(45)) // Outputs 30.0
println(getTime(60)) // Outputs 40.0
println(getTime(70)) // Outputs 46.666...
}

How to get the round number if use the given rule

I have a requirement:
I want there is a function, like this, if the number is:323.01 I want return 500.
If the number is 678.60, I want to get the 1000.
If the number is 20.0, I want get 50.
If the number is 8, I want get 10.
like this: if the first number of the number, if less than 5, I want get 5, if more than 5, I want 10.
How to realize this function in Objective-C?
I just think about the this, I only know use % to get the last number of given number, I don't know how to get the first number of the given number.
First I would get number of digits (e.g. for 456 it is 3):
var originalNumber = 456
var counter = 0
var number = originalNumber
while(number != 0){
counter = counter + 1
number = number / 10
}
From there, you can test it for 5 or 10 with exponent of counter.
if (originalNumber < pow(10, counter - 1) * 5){
number = pow(10, counter - 1) * 5
}
else {
number = pow(10, counter)
}
I reused number variable, you can either return it or assign to other variable.
EDIT: just noticed that flag is Objective - C, same applies
Double originalNumber = 456;
int counter = 0;
int number = (int) originalNumber;
while(number != 0) {
counter = counter + 1;
number = number / 10;
}
if(originalNumber < pow(10,counter - 1) * 5){
number = pow(10, counter -1) * 5;
}
else {
number = pow(10, counter)
}