How do I use "for" for this case - kotlin

I need this function to look in a file for a certain day, then say for each flight how many people are there, in the same day.
So far I managed to get it to say how many people there are per day, but im struggling to get it to say how many people are on each flight per day.
fun interval(reserves: ArrayList<Reserves>, dayInferior: Int, daySuperior: Int) {
var count = dayInferior
var person: Int
for (reserve in reserves) {
person = 0
for (reserve in reserves) {
if (reserve.day == count && reserve.day <= daySuperior) {
person++
}
}
if (count <= daySuperior) {
println("${reserve.numFlight} Day $count has $person")
}
count++
}
}
class Reserves {
var numCc: Int?
var name: String
var numFlight: String
var day: Int
constructor(numCc: Int?, name: String, numFlight: String, day: Int) {
this.numCc = numCc
this.name = name
this.numFlight = numFlight
this.day = day
}
}
fun readFileReserves(fileNameInput: String): ArrayList<Reserves> {
val reserves: ArrayList<Reserves> = ArrayList()
val lines = File(fileNameInput).readLines()
for (line in lines) {
val parts = line.split(':')
val numCc = parts[0].toIntOrNull()
val name = parts[1]
val numFlight = parts[2]
val day = parts[3].toIntOrNull()
if (day == null || numCc == null) {
println("Invalid day")
} else {
val r = Reserves(numCc, name, numFlight, day)
reserves.add(r)
}
}
return reserves
}

I assume #Jocas means interval to get the count of Reserves between dayInferior and daySuperior.
fun interval(reserves: List<Reserves>, dayInferior: Int, daySuperior: Int) {
val map = mapReserves(reserves)
for(day in dayInferior..daySuperior) {
map.forEach {
val reservesName = it.key.first
val reservesDay = it.key.second
val reservesCount = it.value.count()
if (reservesDay == day)
print("$reservesName has $reservesCount on day passengers $day")
}
}
}
fun mapReserves(reserves: List<Reserves>): Map<Pair<String, Int>, List<Reserves>> {
val map = mutableMapOf<Pair<String, Int>, MutableList<Reserves>>()
reserves.forEach {
val key = it.numFlight to it.day
val list = map[key] ?: mutableListOf()
list.add(it)
map[key] = list
}
return map
}
// This is how you write in Kotlin. Your style is Java.
class Reserves(var numCc: Int, var name: String, var numFlight: String, var day: Int)
// Use abstraction List and MutableList instead of ArrayList
fun readFileReserves(fileNameInput: String): List<Reserves> {
val reserves = mutableListOf<Reserves>()
val lines = File(fileNameInput).readLines()
for (line in lines) {
val parts = line.split(":")
val numCc = parts[0].toIntOrNull()
val name = parts[1]
val numFlight = parts[2]
val day = parts[3].toIntOrNull()
if (day == null || numCc == null) {
println("Invalid day")
} else {
val r = Reserves(numCc, name, numFlight, day)
reserves.add(r)
}
}
return reserves
}

Related

How to parse two data list from one PagingData Source in Android Kotlin?

This is My ViewModle Class
#HiltViewModel
class MainViewModel #Inject constructor(
private val movieRepository: MovieRepository,
private val favMovieRepository: FavMovieRepository
) : ViewModel() {
...
private var _movieState = mutableStateOf(false)
val movieState = _movieState
val nowPlayingMovies: Flow<PagingData<Movie>> = Pager(PagingConfig(pageSize = 10)) {
MoviePagingSource(movieRepository)
}.flow
val popularMovies: Flow<PagingData<Movie>> = Pager(PagingConfig(pageSize = 10)) {
MoviePagingSource(movieRepository)
}.flow
...
fun setListToPopular(){
_movieState.value = true
}
}
PagingSource file is here
class MoviePagingSource(
private val movieRepository: MovieRepository
) : PagingSource<Int , Movie>() {
override suspend fun load(params: LoadParams<Int>): LoadResult<Int, Movie> {
return try {
val nextPage = params.key ?: 1
val nowPlayingMovieResponse = movieRepository.getNowPlayingMovies(nextPage)
val popularMovieResponse = movieRepository.getPopularMovies(nextPage)
LoadResult.Page(
data = nowPlayingMovieResponse.results,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = nowPlayingMovieResponse.page.plus(1)
)
LoadResult.Page(
data = popularMovieResponse.results,
prevKey = if (nextPage == 1) null else nextPage - 1,
nextKey = popularMovieResponse.page.plus(1)
)
} catch (e: Exception) {
LoadResult.Error(e)
}
}
...
}
Here I define two LoadResult one for NowPlaying other for popluar movies.
I want to get the follwing result as expected Below.
Here whenever i choose one result should be in my favour for that i have my Home screen.
#Composable
fun MovieListView(viewModel: MainViewModel) {
val lazyMovieItems = viewModel.nowPlayingMovies.collectAsLazyPagingItems()
val lazyPopularMovieItems = viewModel.popularMovies.collectAsLazyPagingItems()
val movieItems = if (!viewModel.movieState.value) lazyMovieItems else lazyPopularMovieItems
LazyColumn {
item {
Row(... ) {
PopularityDropDown(){
viewModel.setListToPopular()
}
} }
items(movieItems) { item ->
MovieCard(movie = item!!) {
...
)
}else Log.d(TAG, "MovieListView: ${item.original_title} with id ${item.id} It is Not favorite ")
}
}
movieItems.apply {
...
}
}
What should be the way for fetching data from PagingSource ? and please suggest better way for handling NowPlaying and popular movie.

Problem saving data into room db from paging library api response

I have an application built using Jetpack Compose , where i also use paging library 3 to fetch data from db , i have multiple remote mediator where i fetch data and save it directly into database , the issue is that sometimes data gets saved , sometimes not , it goes to the point that sometimes one of the two only gets data stored.
Remote Mediator 1:
#ExperimentalPagingApi
class PopularClothingRemoteMediator #Inject constructor(
private val clothingApi: ClothingApi,
private val clothingDatabase: ClothingDatabase
) : RemoteMediator<Int, Clothing>(){
private val clothingDao = clothingDatabase.clothingDao()
private val clothingRemoteKeysDao = clothingDatabase.clothingRemoteKeysDao()
override suspend fun initialize(): InitializeAction {
val currentTime = System.currentTimeMillis()
val lastUpdated = clothingRemoteKeysDao.getRemoteKeys(clothingId = 1)?.lastUpdated ?: 0L
val cacheTimeout = 1440
val diffInMinutes = (currentTime - lastUpdated) / 1000 / 60
return if (diffInMinutes.toInt() <= cacheTimeout) {
// Log.d("RemoteMediator", "UP TO DATE")
InitializeAction.SKIP_INITIAL_REFRESH
} else {
// Log.d("RemoteMediator", "REFRESH")
InitializeAction.LAUNCH_INITIAL_REFRESH
}
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, Clothing>): MediatorResult {
return try {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextPage?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
val prevPage = remoteKeys?.prevPage
?: return MediatorResult.Success(
endOfPaginationReached = remoteKeys != null
)
prevPage
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
val nextPage = remoteKeys?.nextPage
?: return MediatorResult.Success(
endOfPaginationReached = remoteKeys != null
)
nextPage
}
}
val response = clothingApi.getPopularClothing(page = page)
if (response.popularClothing.isNotEmpty()) {
clothingDatabase.withTransaction {
if (loadType == LoadType.REFRESH) {
clothingDao.deleteAllClothing()
clothingRemoteKeysDao.deleteAllRemoteKeys()
}
val prevPage = response.prevPage
val nextPage = response.nextPage
val keys = response.popularClothing.map { clothing ->
ClothingRemoteKeys(
clothingId = clothing.clothingId,
prevPage = prevPage,
nextPage = nextPage,
lastUpdated = response.lastUpdated
)
}
// When i debug this code , it works fine and the last line is executed
// the issue data sometimes gets saved , sometimes not
clothingRemoteKeysDao.addAllRemoteKeys(clothingRemoteKeys = keys)
clothingDao.addClothing(clothing = response.popularClothing)
}
}
MediatorResult.Success(endOfPaginationReached = response.nextPage == null)
} catch (e: Exception) {
return MediatorResult.Error(e)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Clothing>
): ClothingRemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.clothingId?.let { clothingId ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothingId)
}
}
}
private suspend fun getRemoteKeyForFirstItem(
state: PagingState<Int, Clothing>
): ClothingRemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { clothing ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothing.clothingId)
}
}
private suspend fun getRemoteKeyForLastItem(
state: PagingState<Int, Clothing>
): ClothingRemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { clothing ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothing.clothingId)
}
}
}
Remote Mediator 2:
class OuterwearRemoteMediator #Inject constructor(
private val clothingApi: ClothingApi,
private val clothingDatabase: ClothingDatabase
) : RemoteMediator<Int, Clothing>() {
private val clothingDao = clothingDatabase.clothingDao()
private val clothingRemoteKeysDao = clothingDatabase.clothingRemoteKeysDao()
override suspend fun initialize(): InitializeAction {
val currentTime = System.currentTimeMillis()
val lastUpdated = clothingRemoteKeysDao.getRemoteKeys(clothingId = 1)?.lastUpdated ?: 0L
val cacheTimeout = 1440
val diffInMinutes = (currentTime - lastUpdated) / 1000 / 60
return if (diffInMinutes.toInt() <= cacheTimeout) {
// Log.d("RemoteMediator", "UP TO DATE")
InitializeAction.SKIP_INITIAL_REFRESH
} else {
// Log.d("RemoteMediator", "REFRESH")
InitializeAction.LAUNCH_INITIAL_REFRESH
}
}
override suspend fun load(loadType: LoadType, state: PagingState<Int, Clothing>): MediatorResult {
return try {
val page = when (loadType) {
LoadType.REFRESH -> {
val remoteKeys = getRemoteKeyClosestToCurrentPosition(state)
remoteKeys?.nextPage?.minus(1) ?: 1
}
LoadType.PREPEND -> {
val remoteKeys = getRemoteKeyForFirstItem(state)
val prevPage = remoteKeys?.prevPage
?: return MediatorResult.Success(
endOfPaginationReached = remoteKeys != null
)
prevPage
}
LoadType.APPEND -> {
val remoteKeys = getRemoteKeyForLastItem(state)
val nextPage = remoteKeys?.nextPage
?: return MediatorResult.Success(endOfPaginationReached = remoteKeys != null)
nextPage
}
}
val response = clothingApi.getOuterwear(page = page)
if (response.outerwear.isNotEmpty()) {
clothingDatabase.withTransaction {
if (loadType == LoadType.REFRESH) {
clothingDao.deleteAllClothing()
clothingRemoteKeysDao.deleteAllRemoteKeys()
}
val prevPage = response.prevPage
val nextPage = response.nextPage
val keys = response.outerwear.map { clothing ->
ClothingRemoteKeys(
clothingId = clothing.clothingId,
prevPage = prevPage,
nextPage = nextPage,
lastUpdated = response.lastUpdated
)
}
// the same thing here
// When i debug this code , it works fine and the last line is executed
// the issue data sometimes gets saved , sometimes not
clothingRemoteKeysDao.addAllRemoteKeys(clothingRemoteKeys = keys)
clothingDao.addClothing(clothing = response.outerwear)
}
}
MediatorResult.Success(endOfPaginationReached = response.nextPage == null)
} catch (e: Exception) {
return MediatorResult.Error(e)
}
}
private suspend fun getRemoteKeyClosestToCurrentPosition(
state: PagingState<Int, Clothing>): ClothingRemoteKeys? {
return state.anchorPosition?.let { position ->
state.closestItemToPosition(position)?.clothingId?.let { clothingId ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothingId)
}
}
}
private suspend fun getRemoteKeyForFirstItem(
state: PagingState<Int, Clothing>): ClothingRemoteKeys? {
return state.pages.firstOrNull { it.data.isNotEmpty() }?.data?.firstOrNull()
?.let { clothing ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothing.clothingId)
}
}
private suspend fun getRemoteKeyForLastItem(
state: PagingState<Int, Clothing>
): ClothingRemoteKeys? {
return state.pages.lastOrNull { it.data.isNotEmpty() }?.data?.lastOrNull()
?.let { clothing ->
clothingRemoteKeysDao.getRemoteKeys(clothingId = clothing.clothingId)
}
}

Kotlin - The method returns how many elements meet the condition

I'm struggling to get this working:
Implement the method countWhere (condition: (T) -> Boolean): Int. The method returns how many elements meet the condition (state).
Here is an example of how it can be used:
NOTE: I can't change the fun main stuff.
fun main () {
val list = LinkedList <String> ()
list . addFirst ("Apple")
list . addFirst ("Banana")
list . addFirst ("Bear")
val fruitStartsWithB = list. countWhere {element ->
element. starts with ("B")
}
println (fruitStartsWithB) // fruitsStartsWithB is 2 because there are two items in the list that go into "B".
}
this is what causing me troubles:
fun countWhere(condition: (T) -> Boolean): Int {
var count: Int = 0
forEach { if (this == condition) count++ }
return count
}
my return is 0. My return has to be 2. Where is my mistake and how do I fix it?
This is all the code I have:
class LinkedList <T>: Iterable<T> {
data class Node <T>( val data : T, var next : Node <T>?)
private var first : Node <T>? = null
var isSorted = true
fun isEmpty() = first == null
fun addFirst(data: T) {
first = Node(data, first)
isSorted = false
}
fun getFirst(): T = get(0)
fun get(n: Int): T {
if (n < 0 ) throw IndexOutOfBoundsException ()
var run = first
var count = 0
while (count < n && run != null) {
run = run.next
count++
}
return run?.data ?: throw IndexOutOfBoundsException ()
}
fun clear () {
first = null // Clear
isSorted = true // Clear
}
// fun size (): Int{
// var run = first
// var count = 0
// while (run != null) {
// count++
// run = run.next
// }
// return count
// }
fun getOrNull(index: Int): T? {
if (index < 0 ) return null
var run = first
var count = 0
while (count < index && run != null) {
run = run.next
count++
}
return run?.data ?: null
}
fun addLast (data: T){
if (isEmpty()) addFirst(data) else {
var runPointer = first
while (runPointer?.next != null) {
runPointer = runPointer.next
}
runPointer?.next = Node(data, null)
}
isSorted = false
}
fun forEach(action: (T) -> Unit) {
for (i in this ) action(i)
}
fun size (): Int{
var count = 0
forEach { count ++ }
return count
}
override fun iterator(): Iterator<T> = object: Iterator <T> {
private var run = first
override fun hasNext(): Boolean = run!= null
override fun next(): T {
val res = run?.data ?: throw NoSuchElementException()
run = run?.next
return res
}
}
fun countWhere(condition: (T) -> Boolean): Int {
var count: Int = 0
forEach { if (condition(it)) count++ }
return count
}
}
you have to invoke your lambda:
fun countWhere(condition: (T) -> Boolean): Int {
var count: Int = 0
forEach { if (condition(it)) count++ }
return count
}

Kotlin String url params

I have a string url like this:
exampleUrl = www.example.com/test?item=param1=1&param2=11&param3=111&item=param1=2&param2=22&param3=222
and i want to extract from it a Map of key values using item as key.
I wrote the below function
fun String.getUrlParams(): Map<String, List<String>> {
val params = HashMap<String, List<String>>()
val urlParts = this.split("\\?".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
if (urlParts.size > 1) {
val query = urlParts[1]
for (param in query.split("item=".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()) {
System.out.println(param)
val key = "item"
var value = URLDecoder.decode(param, "UTF-8")
var values: MutableList<String>? = params[key] as MutableList<String>?
if (values == null) {
values = ArrayList()
params[key] = values as ArrayList<String>
}
values?.add(value)
}
}
return params
}
But on printed data i am getting this -> {item=[, param1=1&param2=11&param3=111&, param1=2&param2=22&param3=222]}. It has an empty value on start and the & symbol on the end of second value.
The correct one should be -> {item=[param1=1&param2=11&param3=111, param1=2&param2=22&param3=222]}
What am i missing?
Thanks in advance
Splitting on something that appears right at the start or end of a String will give you an empty String at the start or end of the results.
Instead of dropLastWhile you can filter all empty Strings.
You can use "&?item=" to avoid having the trailing & in your first block.
After removing the unnecessary toTypedArray() and Java-specific code you have:
fun String.getUrlParams(): Map<String, List<String>> {
val params = HashMap<String, List<String>>()
val urlParts = split("\\?".toRegex()).filter(String::isNotEmpty)
if (urlParts.size > 1) {
val query = urlParts[1]
for (param in query.split("&?item=".toRegex()).filter(String::isNotEmpty)) {
val key = "item"
val value = URLDecoder.decode(param, "UTF-8")
var values: MutableList<String>? = params[key] as MutableList<String>?
if (values == null) {
values = ArrayList()
params[key] = values
}
values.add(value)
}
}
return params
}
Cleaning it up a bit gives:
fun String.getUrlParams(): Map<String, List<String>> {
val urlParts = split("\\?".toRegex()).filter(String::isNotEmpty)
if (urlParts.size < 2) {
return emptyMap()
}
val query = urlParts[1]
return listOf("item").associateWith { key ->
query.split("&?$key=".toRegex()).filter(String::isNotEmpty)
.map { URLDecoder.decode(it, "UTF-8") }
}
}

RxJava different output between Flowable and Observable with Window and Groupby

I'm using RxJava2 with code that boils down to something like this:
val whitespaceRegex = Regex("\\s+")
val queryRegex = Regex("query=([^&]+)", RegexOption.IGNORE_CASE)
val dateTimeFormatter = DateTimeFormatter.ISO_OFFSET_DATE_TIME
#JvmStatic
fun main(args: Array<String>) {
val cnt = AtomicLong()
val templateStr = "|date| /ignored/ query=|query|"
val random = ThreadLocalRandom.current()
var curDate = ZonedDateTime.of(LocalDate.of(2016, Month.JANUARY, 1), LocalTime.MIDNIGHT, ZoneId.of("UTC"))
val generator = Flowable.generate<String> { emitter ->
// normally these are read from a file, this is for the example
val next = cnt.incrementAndGet()
if (next % 3000 == 0L) {
curDate = curDate.plusDays(1)
}
if (next < 100000) {
val curStr = templateStr
.replace("|date|", dateTimeFormatter.format(curDate))
.replace("|query|", random.nextInt(1, 1000).toString())
emitter.onNext(curStr)
} else {
emitter.onComplete()
}
}
val source = generator
.map { line ->
val cols = line.split(whitespaceRegex)
val queryRaw = queryRegex.find(cols[2])?.groupValues?.get(1) ?: ""
val query = URLDecoder.decode(queryRaw, Charsets.UTF_8.name()).toLowerCase().replace(whitespaceRegex, " ").trim()
val date = dateTimeFormatter.parse(cols[0])
Pair(LocalDate.from(date), query)
}
.share()
source
.window(source.map { it.first }.distinctUntilChanged())
.flatMap { window ->
window
.groupBy { pair -> pair }
.flatMap({ grouping ->
grouping
.count()
.map {
Pair(grouping.key, it)
}.toFlowable()
})
}
.subscribe({ println("Result: $it}") }, { it.printStackTrace() }, { println("Done") })
}
When I use Observable.generate it works fine, but with Flowable.generate there is no output. This is counting how many queries occurred on a given day. The day increase sequentially so I form a window of each day, then count the queries with a groupBy. Do I need to do this differently with Flowable?
As akarnokd mentioned, this was due to flatMap having a default maxConcurrency of 128. I found this issue, https://github.com/ReactiveX/RxJava/issues/5126, which describes the reason in more detail. This fixes the problem:
val cnt = AtomicLong()
val templateStr = "|date| /ignored/ query=|query|"
val random = ThreadLocalRandom.current()
var curDate = ZonedDateTime.of(LocalDate.of(2016, Month.JANUARY, 1), LocalTime.MIDNIGHT, ZoneId.of("UTC"))
val generator = Flowable.generate<String> { emitter ->
val next = cnt.incrementAndGet()
if (next % 3000 == 0L) {
curDate = curDate.plusDays(1)
}
if (next < 1000000) {
val curStr = templateStr
.replace("|date|", dateTimeFormatter.format(curDate))
.replace("|query|", random.nextInt(1, 1000).toString())
emitter.onNext(curStr)
} else {
emitter.onComplete()
}
}
val source = generator
.map { line ->
val cols = line.split(whitespaceRegex)
val queryRaw = queryRegex.find(cols[2])?.groupValues?.get(1) ?: ""
val query = URLDecoder.decode(queryRaw, Charsets.UTF_8.name()).toLowerCase().replace(whitespaceRegex, " ").trim()
val date = dateTimeFormatter.parse(cols[0])
Pair(LocalDate.from(date), query)
}
.share()
source
.window(source.map { it.first }.distinctUntilChanged().doOnEach({println("Win: $it")}))
.flatMap( { window ->
window
.groupBy { pair -> pair }
.flatMap({ grouping ->
grouping
.count()
.map {
Pair(grouping.key, it)
}.toFlowable()
// fix is here
}, Int.MAX_VALUE)
// and here
}, Int.MAX_VALUE)
.subscribe({ println("Result: $it}") }, { it.printStackTrace() }, { println("Done") })