Wrong output. JetBrains Academy - kotlin

I'm working on minesweeper project at JetBrainsAcademy. The code runs, but I got compiler output: "One of the lines of the field doesn't have 9 symbols, but has 12.
This line is "1│.........|"".
Objectives:
Your program should ask the player to define the number of mines to add to a 9x9 field with the message "How many mines do you want on the field?". It should then use the input to initialize the field and display it with the mines. At this point, the mines are still visible to the player; you will hide them later.
Make sure to use the following marking symbols:
X for mines
. for safe cells.
I will be grateful for your help. Sorry, my english is bad
package minesweeper
import kotlin.random.Random
const val SIZE = 9
fun main() {
println("How many mines do you want on the field?")
val numberOfMines = readln().toInt()
println(Board(SIZE))
val (x, y, _) = readln().split(" ")
val board = Board(SIZE, numberOfMines, mapOf("x" to x.toInt() - 1, "y" to y.toInt() - 1))
while (board.isNotWon()) {
val (x, y, action) = readln().split(" ")
val notMine = Pair(x.toInt() - 1, y.toInt() - 1)
when (action) {
"free" -> {
if (board.checkCell(notMine.first, notMine.second)) board.endGame()
else board.explore(notMine.first, notMine.second)
}
"mine" -> {
board.toggleMarking(notMine.first, notMine.second)
}
}
println(board)
}
println(board)
}
data class Cell(private val x: Int, private val y: Int, var isMine: Boolean = false) {
private var number = 0
var isMarked = false
var isExplored = false
fun add() = number++
fun notHasMinesAround(): Boolean = number > 0
fun makeMine() {
isMine = true
}
fun toggleMark() {
isMarked = !isMarked
}
fun explore() {
isExplored = true
isMarked = false
}
fun showMine() {
if (isMine) explore()
}
override fun toString(): String {
return if (isMarked) "*" else if (!isExplored) "." else if (isMine) "X" else if (number == 0) "/" else number.toString()
}
fun isNotMine(): Boolean = !isMine
}
data class Board(
override val size: Int, val numberOfMines: Int = 0, val notMine: Map<String, Int> = emptyMap()
) : MutableList<MutableList<Cell>> by mutableListOf(mutableListOf()) {
private val mines = mutableSetOf<Cell>()
private val markedCells = mines
private val unExploredCells = mines
init {
this.clear()
for (x in indices) {
val line = mutableListOf<Cell>()
for (y in indices) {
line.add(Cell(x, y))
unExploredCells.add(line[y])
}
this.add(line)
}
setMines()
if (notMine.isNotEmpty()) this[notMine["x"]!!][notMine["y"]!!].explore()
}
private fun setMines() {
var minesToSet = numberOfMines
while (minesToSet != 0) {
val x = Random.nextInt(0, SIZE - 1)
val y = Random.nextInt(0, SIZE)
val cell = this[x][y]
if (!cell.isMine && x != notMine["x"] && y != notMine["y"]) {
if (!cell.isMine && !(x == notMine["x"] && y == notMine["y"])) {
cell.makeMine()
minesToSet--
mines.add(cell)
for (row in arrayOf(x - 1, x, x + 1)) {
if (row in indices) for (column in arrayOf(
y - 1, y, y + 1
)) if (column in indices) this[row][column].add()
}
}
}
}
}
fun checkCell(x: Int, y: Int): Boolean = this[x][y].isMine
fun toggleMarking(x: Int, y: Int) {
val y = y - 1
val cell = this[x][y]
cell.toggleMark()
if (cell.isMarked) markedCells.add(cell)
else markedCells.remove(cell)
}
fun endGame() {
this.forEach { it -> it.forEach { it.showMine() } }
println("You stepped on a mine and failed!")
}
fun explore(x: Int, y: Int) {
val cell = this[x][y]
if (!cell.isExplored) {
cell.explore()
unExploredCells.remove(cell)
for (row in arrayOf(x - 1, x, x + 1)) {
if (row in this.indices)
for (column in arrayOf(y - 1, y, y + 1)) {
if (column in this.indices && cell.isNotMine() && cell.notHasMinesAround())
this[row][column].explore()
}
}
}
}
fun isNotWon(): Boolean = !(markedCells == mines || unExploredCells == mines)
override fun toString(): String {
var output = ""
for (i in indices) output += this[i].joinToString(separator = "", prefix = "${i + 1}│", postfix = "|\n")
return output
}
}

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.

Kotlin numerical parser cannot work with `10` and gives E+ when multiplying with 10

Expected output: 3650
I have tested my code with many numerical expressions, all gives correct answers. Only 10 is creating all the problem
My MParser.kt file
package com.parser
import java.math.BigDecimal
import java.math.RoundingMode
class MParser(private var mainExp: String) {
var originalExp: String = ""
init {
println(mainExp)
mainExp = mainExp.dePrettify()
originalExp = mainExp
}
fun calc(): String {
calcD()
calcM()
rearrange()
calcA()
calcMi()
if (mainExp==originalExp)
return "Hello"
return mainExp
}
private fun dividable(): MutableList<String> {
val divisible = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(/+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
divisible.add(it.value)
}
}
return divisible
}
private fun calcD() {
dividable().forEach {
mainExp = mainExp.replace(it, divide(it).toString())
}
}
private fun divide(exp: String): BigDecimal {
val num = toDoubleMutableList(exp.split("/").toMutableList())
while (num.size > 1) {
val dividend = num[0]
val divisor = num[1]
val quotient = dividend.divide(divisor, 3, RoundingMode.HALF_UP)
num[0] = quotient
num.removeAt(1)
}
return num[0]
}
private fun multiplies(): MutableList<String> {
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(\\*+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcM() {
multiplies().forEach {
mainExp = mainExp.replace(it, multiply(it).toString())
}
}
private fun multiply(exp: String): BigDecimal {
val num = toDoubleMutableList(exp.split("*").toMutableList())
while (num.size > 1) {
val factor1 = num[0]
val factor2 = num[1]
val product = factor1 * factor2
num[0] = product
num.removeAt(1)
}
return num[0]
}
private fun addable(): MutableList<String> {
// 5*9*69/3/99+45-78*6/3/2-89 = sample
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(\\++(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcA() {
addable().forEach {
mainExp = mainExp.replace(it, add(it).toString())
}
}
private fun add(exp: String): BigDecimal {
val num = toDoubleMutableList(exp.split("+").toMutableList())
while (num.size > 1) {
val addend1 = num[0]
val addend2 = num[1]
val sum = addend1 + addend2
num[0] = sum
num.removeAt(1)
}
return num[0]
}
private fun minusable(): MutableList<String> {
// 5*9*69/3/99+45-78*6/3/2-89 = sample
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(-+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcMi() {
minusable().forEach {
mainExp = mainExp.replace(it, minus(it).toString())
}
}
fun minus(exp: String): BigDecimal {
val num = toDoubleMutableList(exp.split("-").toMutableList())
while (num.size > 1) {
val addend1 = num[0]
val addend2 = num[1]
val sum = addend1 - addend2
num[0] = sum
num.removeAt(1)
}
return num[0]
}
/*
Utility -- Methods
*/
private fun rearrange() {
val subtracts = mutableListOf<String>()
Regex("(-(\\d+\\.*\\d*))").apply {
this.findAll(mainExp).forEach {
subtracts.add(it.value)
}
}
subtracts.forEach {
mainExp = mainExp.replaceFirst(it, "")
mainExp += it
}
if (mainExp.startsWith("+"))
mainExp = mainExp.replaceFirst("+", "")
}
fun isParenthesisValid(): Boolean {
var valid = true
val stack = ArrayDeque<Char>()
for (symb in mainExp) {
if (symb == '(' || symb == '[' || symb == '{')
stack.addLast(symb)
else if (symb == ')' || symb == ']' || symb == '}') {
if (stack.isEmpty())
valid = false
else {
val i = stack.removeLast()
if (i == '(' && symb != ')' || i == '{' && symb != '}' || i == '[' && symb != ']')
valid = false
} //end else
}
println("stack: $stack")
} //end for-loop
if (stack.isNotEmpty())
valid = false
return valid
}
private fun String.dePrettify(): String {
return this.replace(" ", "").replace("÷", "/").replace("×", "*")
}
fun optimize(exp: String): String {
return exp.replace(" ", "").replace("÷", "/").replace("×", "*")
}
}
fun toDoubleMutableList(list: MutableList<String>): MutableList<BigDecimal> {
val tempList = mutableListOf<BigDecimal>()
for (i in list) {
val b = BigDecimal(i.toDouble().toString()).stripTrailingZeros()
tempList.add(b)
}
return tempList
}
When I do val value = try {MParser("365*10").calc()} catch (e: NumberFormatException) {"Error"} in another .kt file, I am getting value = 3.65E+3
How is the E+ appearing?
I have debugged the code.
I think the problem starts from calcMi(). Check it once as I cannot understand what to do.
Expressions that I have tested and were coorect:
//whole numbers
val wexp0 = "12 + 4 - 8 ÷ 2 × 3".optimize() //4
val wexp1 = "7 - 5 + 14 ÷ 2 + 6".optimize() //15
val wexp2 = "37 - 6 × 4 + 32 ÷ 8".optimize() //17
val wexp3 = "64 - 48 ÷ 6 × 4 + 8".optimize() //40
//decimal numbers
val dexp0 = "5*9*69/3/99+45-78*6/3/2-89-4/5+62.2/2/4"
val dexp1 = "-5+4-4+1-78+86-21+9+5-5-1+9.787-2+1000"
val dexp2 = "0.2 + 1.3 - 0.4 × 1.5".optimize() //0.9
val dexp3 = "0.3 × 0.4 - 2.4 ÷ 6 + 1.2 × 4".optimize() //4.52
val dexp4 = "0.72 ÷ 1.2 + 3.5 × 4.2 - 1.6".optimize() //13.7
val dexp5 = "9.2 + 3.5 - 4.9 - 3.5 ÷ 0.7 × 1.2".optimize() //1.8
val dexp6 = "95.01 × 1.2 - 2.4 ÷ 2".optimize() //4.812
But as you can see I never used 10 in any of the above. And suddenly when I used 10, I spotted the issue.
Please see the debug-image carefully. 10 gets converted to 1E+1 even before the multiplication is done.
Finally solved the problem.
I have changed all the return types of minus(), add(), multiply(), divide() to string instead of keeping itBigDecimal.
Each of these methods were returning BigDecimal due to which I was getting the E+ in my output. But I observed that all the returned values from these methods were finally added to a String
So after the calculations I applied toPlainString() to the BigDecimal that were returned.
By doing this, the E+ does not appear in the output and I also don't have to manage the trailing zeros one by one.
New code
package com.parser
import java.math.BigDecimal
import java.math.RoundingMode
class MParser(private var mainExp: String) {
var originalExp: String = ""
init {
println(mainExp)
mainExp = mainExp.dePrettify()
originalExp = mainExp
}
fun calc(): String {
calcD()
calcM()
rearrange()
calcA()
calcMi()
if (mainExp==originalExp)
return "Hello"
return mainExp
}
private fun dividable(): MutableList<String> {
val divisible = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(/+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
divisible.add(it.value)
}
}
return divisible
}
private fun calcD() {
dividable().forEach {
mainExp = mainExp.replace(it, divide(it).toString())
}
}
private fun divide(exp: String): String {
val num = toDoubleMutableList(exp.split("/").toMutableList())
while (num.size > 1) {
val dividend = num[0]
val divisor = num[1]
val quotient = dividend.divide(divisor, 3, RoundingMode.HALF_UP)
num[0] = quotient
num.removeAt(1)
}
return num[0].toPlainString()
}
private fun multiplies(): MutableList<String> {
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(\\*+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcM() {
multiplies().forEach {
mainExp = mainExp.replace(it, multiply(it).toString())
}
}
private fun multiply(exp: String): String {
val num = toDoubleMutableList(exp.split("*").toMutableList())
while (num.size > 1) {
val factor1 = num[0]
val factor2 = num[1]
val product = factor1 * factor2
num[0] = product.stripTrailingZeros()
num.removeAt(1)
}
return num[0].toPlainString()
}
private fun addable(): MutableList<String> {
// 5*9*69/3/99+45-78*6/3/2-89 = sample
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(\\++(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcA() {
addable().forEach {
mainExp = mainExp.replace(it, add(it).toString())
}
}
private fun add(exp: String): String {
val num = toDoubleMutableList(exp.split("+").toMutableList())
while (num.size > 1) {
val addend1 = num[0]
val addend2 = num[1]
val sum = addend1 + addend2
num[0] = sum
num.removeAt(1)
}
return num[0].toPlainString()
}
private fun minusable(): MutableList<String> {
// 5*9*69/3/99+45-78*6/3/2-89 = sample
val multiplies = mutableListOf<String>()
Regex("(\\d+\\.*\\d*)(-+(\\d+\\.*\\d*))+").apply {
this.findAll(mainExp).toMutableList().forEach {
multiplies.add(it.value)
}
}
return multiplies
}
private fun calcMi() {
minusable().forEach {
mainExp = mainExp.replace(it, minus(it).toString())
}
}
fun minus(exp: String): String {
val num = toDoubleMutableList(exp.split("-").toMutableList())
while (num.size > 1) {
val addend1 = num[0]
val addend2 = num[1]
val sum = addend1 - addend2
num[0] = sum
num.removeAt(1)
}
return num[0].toPlainString()
}
/*
Utility -- Methods
*/
private fun rearrange() {
val subtracts = mutableListOf<String>()
Regex("(-(\\d+\\.*\\d*))").apply {
this.findAll(mainExp).forEach {
subtracts.add(it.value)
}
}
subtracts.forEach {
mainExp = mainExp.replaceFirst(it, "")
mainExp += it
}
if (mainExp.startsWith("+"))
mainExp = mainExp.replaceFirst("+", "")
}
fun isParenthesisValid(): Boolean {
var valid = true
val stack = ArrayDeque<Char>()
for (symb in mainExp) {
if (symb == '(' || symb == '[' || symb == '{')
stack.addLast(symb)
else if (symb == ')' || symb == ']' || symb == '}') {
if (stack.isEmpty())
valid = false
else {
val i = stack.removeLast()
if (i == '(' && symb != ')' || i == '{' && symb != '}' || i == '[' && symb != ']')
valid = false
} //end else
}
println("stack: $stack")
} //end for-loop
if (stack.isNotEmpty())
valid = false
return valid
}
private fun String.dePrettify(): String {
return this.replace(" ", "").replace("÷", "/").replace("×", "*")
}
fun optimize(exp: String): String {
return exp.replace(" ", "").replace("÷", "/").replace("×", "*")
}
}
fun toDoubleMutableList(list: MutableList<String>): MutableList<BigDecimal> {
val tempList = mutableListOf<BigDecimal>()
for (i in list) {
val b = BigDecimal(i).stripTrailingZeros()
tempList.add(b)
}
return tempList
}

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
}

DiffUtil areContentsTheSame() always returns true, after the contents are updated of the List in RecycleViewAdapter

This is my RecyclerView Adapter Class. Clicking an item from the list UI should change of the particular item like background black to white. After clicking an item I am changing the status of the item 0 to 1 from the UI class, based on that status UI should change of the item. But inside diffUtil areContentTheSame() retures true.
class TimeSlotsAdapter(val adapterItemOnClick: (TimeSlots) -> Unit):RecyclerView.Adapter<TimeSlotsAdapter.TimeSlotsViewHolder>() {
private lateinit var binding: RvTimeSlotsBinding
private var timeSlots: List<TimeSlots> = ArrayList<TimeSlots>()
inner class TimeSlotsViewHolder : RecyclerView.ViewHolder {
constructor(rvBinding: RvTimeSlotsBinding) : super(rvBinding.root) {
}
fun setItem(timeSlots: TimeSlots) {
binding.timeSlotView.setOnClickListener { adapterItemOnClick(timeSlots) }
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): TimeSlotsViewHolder {
binding =
RvTimeSlotsBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return TimeSlotsViewHolder(binding)
}
override fun onBindViewHolder(holder: TimeSlotsViewHolder, position: Int) {
timeSlots[position]?.let { currentSlot ->
with(holder) {
if (currentSlot.status == "1") {
binding.timeSlotView.background =
ContextCompat.getDrawable(
binding.timeSlotView.context,
R.drawable.time_slot_item_bg
)
binding.timeSlotTv.setTextColor(
ContextCompat
.getColor(binding.timeSlotTv.context, R.color.black)
)
binding.timeSlotTv.text = "1 " + currentSlot.time
Timber.e("${currentSlot.time} ${currentSlot.status}")
} else {
binding.timeSlotView.background =
ContextCompat.getDrawable(
binding.timeSlotView.context,
R.drawable.black_bg
)
binding.timeSlotTv.setTextColor(
ContextCompat
.getColor(binding.timeSlotTv.context, R.color.white)
)
binding.timeSlotTv.text = "0 " + currentSlot.time
Timber.e("${currentSlot.time} ${currentSlot.status}")
}
setItem(currentSlot)
}
}
}
override fun getItemCount(): Int = timeSlots.size
fun submitSlots(timeSlotList: List<TimeSlots>) {
val oldList = timeSlots
val diffResult: DiffUtil.DiffResult = DiffUtil.calculateDiff(
TimeSlotsDiffCallBack(
oldList,
timeSlotList
)
)
timeSlots = timeSlotList
diffResult.dispatchUpdatesTo(this)
}
class TimeSlotsDiffCallBack(
var oldTimeSlotsList: List<TimeSlots>,
var newTimeSlotsList: List<TimeSlots>
) : DiffUtil.Callback() {
override fun getOldListSize(): Int = oldTimeSlotsList.size
override fun getNewListSize(): Int = newTimeSlotsList.size
override fun areItemsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
return (oldTimeSlotsList[oldItemPosition].time
== newTimeSlotsList[newItemPosition].time)
}
override fun areContentsTheSame(oldItemPosition: Int, newItemPosition: Int): Boolean {
val oldTimeSlots = oldTimeSlotsList[oldItemPosition].status
val newTimeSlots = newTimeSlotsList[newItemPosition].status
Timber.e("old: $oldTimeSlots new: $newTimeSlots")
return oldTimeSlots == newTimeSlots
}
}
}
This is the UI class for submitting adapter list. Below the doClickTimeSlot() I am updating the status of the items.
class TimeSlotBottomSheetFragment : BottomSheetDialogFragment(){
private val obj: List<TimeSlots> = mutableListOf<TimeSlots>(
TimeSlots("09:30", "0"),
TimeSlots("10:30", "0"),
TimeSlots("11:30", "0"),
TimeSlots("12:30", "0"),
TimeSlots("14:30", "0"),
TimeSlots("15:30", "0"),
TimeSlots("16:30", "0"),
TimeSlots("17:30", "0"),
TimeSlots("18:30", "0"),
TimeSlots("19:30", "0"),
TimeSlots("20:30", "0"),
TimeSlots("21:30", "0")
)
private fun doClickTimeSlot(timeSlots: TimeSlots) {
val newList: ArrayList<TimeSlots> = ArrayList<TimeSlots>()
newList.addAll(obj)
for (i in newList.indices) {
if (newList[i].time == timeSlots.time) {
newList[i].status = "1"
Timber.e("" + newList[i].time + " " + newList[i].status)
} else {
newList[i].status = "0"
Timber.e("" + newList[i].time + " " + newList[i].status)
}
}
adapter.submitSlots(newList)
}
}

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") })