How to use getHour() to get current hour in kotlin - kotlin

fun getHours() = int
val openHours = 7
val now = getHours()
val office: String
office = if (now > 7){
"Office already open"
} else if(now == openHours){
"wait a minute, office will be open"
}else{
"office is closed"
}
println(office)
The following code doesn't seem to get me the current hour from my computer, what am I missing?

The right syntax of defining a function in Kotlin would be:
// function without params and returns Unit
fun functionName1() {}
// function with one parameter and returns Int
fun functionName2(text: String): Int {
return 6
}
// short syntax for one line function with two params and Boolean as return value
fun functionName3(text: String, isVisible: Boolean): Boolean = text.isEmpty && isVisible
Code provided by you has incorrect syntax, please fix it. It should be something like this:
fun getHours(): String {
val openHours = 7
val now = getCurrentHour()
val office = when {
now > 7 -> "Office already open"
now == openHours -> "wait a minute, office will be open"
else -> "office is closed"
}
println(office)
return office
}
fun getCurrentHour(): Int {
// somehow get current hour, for example using java.util.Calendar class
return Calendar.getInstance().get(Calendar.HOUR_OF_DAY)
}

You can get the current system time using LocalDateTime class like :
import java.time.LocalDateTime
val currentDateTime = LocalDateTime.now()
And to get hours specifically you could use DateTimeFormatter class like:
import java.time.format.DateTimeFormatter
currentDateTime.format(DateTimeFormatter.ofPattern("HH"))

Basically, the answer given by #Sergey is correct.
Just one minor nit:
I would not use java.util.Date for it but one of the classes from java.time, see this example:
fun getHours(): String {
val openHours = 7
val now = java.time.ZonedDateTime.now(java.time.ZoneId.systemDefault()).hour
val office = when {
now > 7 -> "Office already open"
now == openHours -> "wait a minute, office will be open"
else -> "office is closed"
}
return office
}
using that in a fun main() like
fun main() {
println(getHours())
}
would then result in the (system dependent) output
office is closed
on my system at 08:48 o'clock in UTC+2.

Related

Kotlin (if else)

I'm new to kotlin. I need to make a calculator using enam. At the end of the code, there is a function that reads the action and returns the enam. The function works but, "if else" doesn't. Need console calculator, not in android studio.Please help!
All code from file
import java.lang.Exception
fun main() {
print("first number: ")
val first : Int = readNumber()
print("second number: ")
val second : Int = readNumber()
println("Enter action: +, -, *, /")
val sum : Int = first + second
println("Answer: $sum ")
}
fun readNumber() :Int{
return try {
readLine()!!.toInt()
}
catch (e:Exception){
0
}
}
enum class Action(val symbol : String){
PLUS("+"),
MINUS("-"),
MULTIPLY("*"),
DIVIDE("/");
}
fun defineAct(){
val pls = Action.PLUS
val mns = Action.MINUS
val mlt = Action.MULTIPLY
val dvd = Action.DIVIDE
if (val = pls){
sum = pls + mns
println("Ответ: ${sum}")
else if (val - mns){
sum = pls - mns
}
}
Your are using val keyword inside if-else. You could change it accordingly your requirements. Hope it will solve your problem.

How to find specific word in objects past 6 months and categories them week by week?

I'm new to Kotlin and trying to figure out how I can do the best way. I have an api call that I call and I convert the response to a list of objects:
data class JobAd(
val published: LocalDate?,
val title: String?,
val jobtitle: String?,
val description: String?
)
On the api call, I search for all job ads that are from today and back in time of 6 months. For example I get all objects which is from LocalDate.now() and 6 months back LocalDate).now().minusMonths(6). I want to iterate through all the objects and see if 2 random words (java and kotlin) are contained in the object. I want to check either title, jobtitle or description contain the word java or kotlin. I only need one hit of the word java or kotlin in these properties, if title contain java or kotlin, add it to list and check next object. If not title contain the words and either jobtitle, but description does it, add it to the list and check next object. and add it to a list based on which week it is.
I want the output to be like this:
(2022) Week 12 -> Java: 0, Kotlin: 1
(2022) Week 11 -> Java: 0, Kotlin: 0 (If some weeks does not have hit, i want to show to too)
...
(2021) Week 52 -> Java: 1, Kotlin: 2
This is my code so far:
private fun findAdsBasedOnKeyWords(jobAds: MutableList<JobAd>, keywords: List<String>, from: LocalDate, to: LocalDate): MutableMap<Any, MutableMap<String, Any>> {
val resultMap = mutableMapOf<Any, MutableMap<String, Any>>()
val counter = mutableMapOf<String, Any>() //Meta data
for (jobAd: JobAd in jobAds) {
for (keyword: String in keywords) {
val weekNumber = DateParser.getWeekNumber(jobAd.published!!)
// Initialize placeholder data, to fill even empty weeks
resultMap.putIfAbsent(weekNumber, emptyMapOfKeywords(keywords, jobAd.published))
// Validate keyword exist in job ad
val contains = jobAd.toString().lowercase()
.contains(keyword.lowercase()) //Can be an issue if the toString gets overridden
if (contains) {
counter.putIfAbsent(keyword, 0)
counter.compute(keyword) { _, v -> v.toString().toInt() + 1 }
resultMap[weekNumber]!!.compute(keyword) { _, v -> v.toString().toInt() + 1 }
}
}
}
resultMap["total"] = counter
resultMap["period"] = mutableMapOf("from" to from, "to" to to)
logger.info("[{}] matches found", counter)
return resultMap
}
//Helper method to generate placeholder data
private fun emptyMapOfKeywords(keywords: List<String>, published: LocalDate): MutableMap<String, Any> {
val keywordMap = mutableMapOf<String, Any>()
for (keyword in keywords) {
keywordMap.putIfAbsent(keyword, 0)
}
keywordMap.putIfAbsent("from", DateParser.startOfWeekDate(published))//Monday of the week
keywordMap.putIfAbsent("to", DateParser.endOfWeekDate(published))//Sunday of the week
return keywordMap
}
Is there any way to do it better or optimize it and please add comment for why.
It's a pretty extreme anti-pattern to use Maps to hold various types of data that you need to inspect. That's trying to force a strongly typed language to behave like a weakly typed language, losing all the protection you get from using types.
Maps are appropriate when the keys are something you don't know at compile time and you know you'll need to look up items by their keys at runtime.
So instead of a MutableMap<Any, MutableMap<String, Any>> return value, you should create classes for holding results. From what I can tell, you want to return a series of line items for every week in the input range, so you can create a class like this to represent a line item, and then return a simple list of them from your function. You are currently also returning the range, but I don't see what you're using it for so I left it out.
You're working with a week of a year a lot, so I think it will also be helpful to have a class to represent that, along with a couple of functions to help convert from LocalDate.
data class LocalWeek(val year: Int, val week: Int)
fun LocalDate.toLocalWeek() = LocalWeek(year, get(IsoFields.WEEK_OF_WEEK_BASED_YEAR))
/** Gets every week represented in a range of dates. */
fun ClosedRange<LocalDate>.toLocalWeeks() = sequence {
var date = start
val lastExclusive = endInclusive + Period.ofWeeks(1)
while (date < lastExclusive ) {
yield(date.toLocalWeek())
date += Period.ofWeeks(1)
}
}
data class JobAdsSearchLineItem(
val localWeek: LocalWeek,
val keywordHitCountsByKeyword: Map<String, Int>
) {
fun toReadableString() =
"(${localWeek.year}) Week ${localWeek.week} -> " +
keywordHitCountsByKeyword.entries
.joinToString { (word, count) -> "$word: $count" }
}
Using toString() is fragile, like you mentioned in your code comments. I would create a helper function like this to evaluate whether a term is found:
fun JobAd.containsIgnoreCase(str: String): Boolean {
val value = str.lowercase()
return title.orEmpty().lowercase().contains(value)
|| jobtitle.orEmpty().lowercase().contains(value)
|| description.orEmpty().lowercase().contains(value)
}
Since you're using !! on your published date, I'm assuming these values don't need to be nullable. It would be much easier to work with if you make the property non-nullable:
data class JobAd(
val published: LocalDate,
val title: String?,
val jobtitle: String?,
val description: String?
)
Then your search function can be written like this:
private fun findAdsBasedOnKeyWords(
jobAds: List<JobAd>,
keywords: List<String>,
from: LocalDate,
to: LocalDate
): List<JobAdsSearchLineItem> {
// Initialize empty results holders representing every week in the range
// Use an outer map here because we need to keep retrieving the inner maps by
// the week when iterating the input below.
val results = mutableMapOf<LocalWeek, MutableMap<String, Int>>()
for (localWeek in (from..to).toLocalWeeks()) {
results[localWeek] = mutableMapOf<String, Int>().apply {
for (keyword in keywords) {
put(keyword, 0)
}
}
}
for (jobAd in jobAds) {
val weekResults = results[jobAd.published.toLocalWeek()] ?: continue
for (keyword in keywords) {
if (jobAd.containsIgnoreCase(keyword)) {
weekResults[keyword] = weekResults.getValue(keyword) + 1
}
}
}
return results.entries.map { JobAdsSearchLineItem(it.key, it.value) }
}
And to use it you can call this function and use the toReadableString() function to help generate your output from the list of results.

Parking lot project error: when using a scanner. NoSuchElementException

I'll appreciate all your help.
I've been working on a course project where I have to make a parking lot that registers cars. When I use it in my IDE it works fine but when I run it through the platforms tests, in the first one, there's no problem but when the second iteration reaches the "when (val command = scanner.next())" in the createOrder fun, it crashes with the error:
java.lang.AssertionError: Exception in test #1
Probably your program run out of input (Scanner tried to read more than expected).
java.util.NoSuchElementException
at java.util.Scanner.throwFor(Scanner.java:862)
at java.util.Scanner.next(Scanner.java:1371)
at parking.ParkingLot.createOrder(Main.kt:39)
at parking.ParkingLot.start(Main.kt:31)
at parking.MainKt.main(Main.kt:6)
at parking.MainKt.main(Main.kt)
Please find below the output of your program during this failed test.
Note that the '>' character indicates the beginning of the input line.
---
> park KA-01-HH-1234 White
White car parked in spot 1.
the idea is that the test inputs many cars but it crashes when trying to do the second input
this is my code (sorry if my code is messy, I'm still learning)
import java.util.*
fun main() {
ParkingLot.start()
}
class Car(val regNumber: String = "", val color: String = "") {
}
class Order(val command: String) {
lateinit var regNum: String
lateinit var color: String
lateinit var spot: String
lateinit var status: String
}
object ParkingLot {
val spaces: Array<Pair<String?, Car?>> = Array(20) { Pair(null, null) }
const val occupied = "occupied"
const val park = "park"
const val leave = "leave"
const val exit = "exit"
fun start() {
val scanner = Scanner(System.`in`)
do {
val order = createOrder(scanner)
interaction(order, scanner)
} while (order.command != exit)
}
fun createOrder(scanner: Scanner): Order {
when (val command = scanner.next()) {
park -> {
val parkOrder = Order(command)
parkOrder.regNum = scanner.next()
parkOrder.color = scanner.next()
parkOrder.status = "valid"
return parkOrder
}
leave -> {
val retrieveOrder = Order(command)
retrieveOrder.spot = scanner.next()
retrieveOrder.status = "valid"
return retrieveOrder
}
exit -> {
val exitOrder = Order(command)
exitOrder.status = "valid"
return exitOrder
}
else -> {
val incorrectOrder = Order(command)
incorrectOrder.status = "invalid"
return incorrectOrder
}
}
}
fun interaction(order: Order, scanner: Scanner) {
if (order.command == park) {
// val toParkCar = Car(order.regNum, order.color)
park(Car(order.regNum, order.color))
}
if (order.command == leave) {
leave(order)
}
if (order.command == exit) return
//TODO update the error msg to include exit command
if (order.status == "invalid") println("\"${order.command}\" isn't a valid , either use \"park\" or \"leave\"")
// scanner.close()
}
fun park(car: Car) {
for ((index, item) in spaces.withIndex()) {
if (item.first == null) {
spaces[index] = Pair(occupied, car)
println("${car.color} car parked in spot ${index + 1}.")
return
}
}
println("Sorry, the parking lot is full.")
}
fun leave(order: Order) {
if (spaces[order.spot.toInt() - 1].first == occupied) {
spaces[order.spot.toInt() - 1] = Pair(null, null)
println("Spot ${order.spot} is free.")
} else {
println("There is no car in spot ${order.spot}.")
}
}
}
Ok so I noticed this is a problem for the JetBrains plugin. I don't know why but the solution was taking the scanner out of the function and directly in the main loop.

Kotlin/Native pigpio Library sigHandler: Unhandled signal 11, terminating

I try to use the pigpio library with Kotlin/Native. To get started I followed this talk:
Bridge The Physical World: Kotlin Native on Raspberry Pi
The sigHandler: Unhandled signal 11, terminating occurs, when I try to assign a value I get from a callback to a global variable lastChange = tick on line 54
The whole code for my testing looks like this:
package ch.lichtwellenreiter.omrr
import kotlinx.cinterop.staticCFunction
import pigpio.*
const val GPIO_BUTTON = 6
var lastChange: UInt = 0u
fun main() {
initGPIO()
println()
setupButton()
println()
while (true) {}
}
private fun initGPIO() {
println("Init GPIO")
if (gpioInitialise() < 0) {
println("GPIO Error initialising")
return
}
}
private fun setupButton() {
println("Setup pin")
val buttonPort = GPIO_BUTTON.toUInt()
initPortWithMode(buttonPort, PI_INPUT)
println("Register callback for pin")
gpioSetAlertFunc(buttonPort, flankChangeDetected)
}
private fun initPortWithMode(port: UInt, mode: Int) {
if (gpioSetMode(port, mode.toUInt()) < 0) {
println("Could not set mode for GPIO$port")
return
}
}
val flankChangeDetected = staticCFunction<Int, Int, UInt, Unit> { gpio, level, tick ->
println("Callback called")
val ticker: UInt = tick
val pin: Int = gpio
val lvl: Int = level
println("Calculate time")
val time = ticker - lastChange
println("Set lastChange")
lastChange = tick
println("Is DCC signal?")
if ((time > 55u && time < 61u) || (time > 113u && time < 119u)) println(time)
println()
}
How can I prevent this error?
After some trying I have found a solution, but don't know if it is the best way to do it.
A global variable as an AtomicInt didn't work, but this way it works:
#SharedImmutable
val sharedData = SharedData()
class SharedData {
var lastChange = AtomicInt(0)
}
This way I can access the valua via val lastChange = sharedData.lastChange.value and sharedData.lastChange.compareAndSet(lastChange, tick.toInt())
I would guess the problem is related to Kotlin/Native immutability rules. This issue I found convinced me to think that the callback is being called not on the main thread. If that's true, the error is caused by violating mutable XOR shared K/N's rule. Cannot write a snippet at the moment, but I think you can either try using AtomicInt or, if it fits the need here, #ThreadLocal annotation.

How can I change this to use "for loop" instead of `forEach`

I'm struggling to change it to use a for loop and still do the same thing.
The program is supposed to read a file with some flights and this specific part of the program needs to read the file using two different days that the user inputs then it needs to show how many passengers there are per flight and each day.
And how it's done now works but I'm trying to change it to use a for loop as I said before but doesn't work because I don't know how to do the same thing as map does but only in the fun interval.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
val map = mapReservas(reservas)
for(day in dayInferior..daySuperior) {
map.forEach {
val reservasNum = it.key.first
val reservasDay = it.key.second
val reservasCount = it.value.count()
if (reservasDay == day) {
println("$reservasNum has $reservasCount passengers on day $day")
}
}
}
println()
println("Press Enter")
readLine()
}
fun mapReservas(reservas: List<Reservas>): Map<Pair<String, Int>, List<Reservas>> {
val map = mutableMapOf<Pair<String, Int>, MutableList<Reservas>>()
for (reserva in reservas) {
val key = reserva.numFlight to reserva.day
val list = map[key] ?: mutableListOf()
list.add(reserva)
map[key] = list
}
return map
}
All your code can be replaced only with one function.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
reservas.groupBy { reserva -> reserva.day to reserva.numFlight }
.filter { (key, _) -> key.first in dayInferior..daySuperior }
.forEach { (key, reservas) ->
val (reservasNum, reservasDay) = key
val reservasCount = reservas.count()
println("$reservasNum has $reservasCount passengers on day $reservasDay")
}
println()
println("Press Enter")
readLine()
}
Explaining:
As I undestand, at first you trying to group all your Reservas by day and numFlight. It can be done via one function groupBy where you pass pair of day and numFlight.
Filter all Reservas by day. It can be done by checking if day belongs to range dayInferior..daySuperior (operator in).
Print all reservas by using forEach.
Other things
Destructing declarations
val reservasNum = it.key.first
val reservasDay = it.key.second
same as
val (reservasNum, reservasDa) = it.key
Omitting one unused parameter in lamda:
.filter { (key, _) -> ... }
If you iterate with a for loop over the Map each element is a Pair. If you write (pair, list) you destructure each Pair which itself consists of a Pair and a List.
fun interval(reservas: List<Reservas>, dayInferior: Int, daySuperior: Int) {
val map = mapReservas(reservas)
for(day in dayInferior..daySuperior) {
for((pair, list) in map) {
val reservasNum = pair.first
val reservasDay = pair.second
val reservasCount = list.count()
// ...
}
}
// ...
}
Maybe this makes it more clear:
for(outerPair in map){
val (innerPair, list) = outerPair
val reservasNum = innerPair.first
val reservasDay = innerPair.second
val reservasCount = list.count()
// ...
}
I left this function (mapReservas) untouched intentionally, because maybe you are using it somewhere else. But you can improve it right away by using Type aliases (since Kotlin 1.1).
typealias FlightNum = String
typealias Day = Int
fun mapReservas(reservas: List<Reservas>):
Map<Pair<FlightNum, Day>, List<Reservas>> {
// ...
}
As you can see the code becomes much more readable if you use the destructure syntax and Type aliases.