Initializing an Array using lambda with conditions in Kotlin - android

Info
I have an Item class file as follows:
class Item(var color:String, var numValue:Int, var drawableID:Int){
init {
color = this.color
numValue = this.numValue
drawableID = this.drawableID
}
}
In the main code I create an array which contains 104 objects by default attributes:
var myItemClassArray = Array(104) { Item("", -99, -99) }
Also I have pictures in my drawable folder and I have their IDs in an array which is drawablesIDs:Array<Int>, and it contains 53 elements.
Problem
I want to assign my Item attributes as in this picture: https://i.stack.imgur.com/wFVsn.png I can do it for a similar problem (which has 106 objects and 53 drawables) with the code given in below:
for (i in 0 until 106) {
if (i < 13) {
myItemClassList[i+2].color = "kirmizi"
myItemClassList[i+2].numValue = i+1
myItemClassList[i+2].drawableID = drawablesIDs[i+1]
} else if (i in 13..25) {
myItemClassList[i+2].color = "siyah"
myItemClassList[i+2].numValue = (i+1)-13
myItemClassList[i+2].drawableID = drawablesIDs[i+1]
} else if (i in 26..38) {
myItemClassList[i+2].color = "yesil"
myItemClassList[i+2].numValue = (i+1)-26
myItemClassList[i+2].drawableID = drawablesIDs[i+1]
} else if (i in 39..51) {
myItemClassList[i+2].color = "mavi"
myItemClassList[i+2].numValue = (i+1)-39
myItemClassList[i+2].drawableID = drawablesIDs[i+1]
} else if (i in 52..64) {
myItemClassList[i+2].color = "kirmizi"
myItemClassList[i+2].numValue = (i+1)-52
myItemClassList[i+2].drawableID = drawablesIDs[(i+1)-52]
} else if (i in 65..77) {
myItemClassList[i+2].color = "siyah"
myItemClassList[i+2].numValue = (i+1)-65
myItemClassList[i+2].drawableID = drawablesIDs[i+1-65+13]
} else if (i in 78..90) {
myItemClassList[i+2].color = "yesil"
myItemClassList[i+2].numValue = (i+1)-78
myItemClassList[i+2].drawableID = drawablesIDs[i+1-78+26]
} else if (i in 91..103) {
myItemClassList[i+2].color = "mavi"
myItemClassList[i+2].numValue = (i+1)-91
myItemClassList[i+2].drawableID = drawablesIDs[i+1-91+39]
} else {
myItemClassList[0].color = "sahte"
myItemClassList[0].drawableID = drawablesIDs[0]
myItemClassList[1].color = "sahte"
myItemClassList[1].drawableID = drawablesIDs[0]
}
}
Is there a cleaner way to do this?
One can use lambda expression to create an array. For example:
val test = Array(28){i-> examples[i]}
This works fine with one "i" parameter. But if I want to try something like this:
val test = Array(28){if(i<13)-> examples[i]}
it gives me an error because of it's syntax is wrong.
More Simple Question
Let's say we have an array which has numbers from 0 to 28 like this:
val testNumbers= Array(28){i->i}
Now I want to create an array which will contain numbers from 0 to 10 using lambda.
How do I this:
val player6 = Array(10){(it<10) -> testNumbers[it]} // gives an syntax error

From what I could gather from your picture, I've made these three assumptions:
The numValue is grouped in groups of 13 items
Each group receives a color in the order: kirmizi -> siyah -> yesil -> mavi, then it cycles again
The drawable IDs cycles every 52 items
Based on this, I came up with the following solution:
data class Item(var color: String = "", var numValue: Int = -99, var drawableId: Int = -99)
fun main() {
val colors = listOf("kirmizi", "siyah", "yesil", "mavi")
val drawableIDs = (0..52).toList() // This is just a stub. in your case it will be your drawable lists
val edgeCase = arrayListOf(Item("sahte", drawableId = drawableIDs[0]), Item("sahte", drawableId = drawableIDs[0]))
val pattern = (0 until 104)
.map { index -> Pair(index, index / 13) }
.map { (index, group) ->
Item(
color = colors[group % 4],
numValue = index+1,
drawableId = drawableIDs[(index % 52) + 1]
)
}
val total = pattern + edgeCase
total.forEach { println(it) }
}
You can play around with it on this kotlin playground.
Is there a cleaner way to do this?
From what I gather, you want to initialize only the first 13 values of a contiguous array with 28 spaces, leaving the rest with either their default values or null.
The reason why your code doesn't work is because the Array initializer expects you to return an object. the if block by itself is not an expression in kotlin, so it doesn't evaluate to a value, so you need to provide an else branch for it to work.
val examples = Array(28) { if (i < 13) examples[i] else defaultExample }
This is stated in the Kotlin documentation for control flow:
If you're using if as an expression rather than a statement (for example, returning its value or assigning it to a variable), the expression is required to have an else branch.
More simple question
In this case you could just use take:
// If you don't want to modify it
val player6 = testNumbers.take(10)
.toTypedArray() // Since take returns a List, you need to turn it back into an array
// If you want to modify the items
val player6 = testNumbers.take(10)
.map { value -> modifyNumber(value) }
.toTypedArray()
Tip: In kotlin if you declare your constructor parameter with val or var they are already attributes from your class and you don't need to initialize manually in the init block.
/*
* You don't need to do this:
* class Item(var color: String, var numValue: Int, var drawableId: Int) {
* init {
* this.color = color
* this.numValue = numValue
* this.drawableId = drawableId
* }
* }
*/
// Kotlin already does it for you
class Item(var color: String, var numValue: Int, var drawableId: Int)
fun main() {
val myitem = Item("blue", 20, 100)
println(myitem.color)
println(myitem.numValue)
println(myitem.drawableId)
}

Here is a possible solution :
fun getColor(i: Int) = when (i) {
in 0..1 -> "sahte"
in 2..13, in 52..64 -> "kirmizi"
in 65..77, in 13..25 -> "siyah"
in 26..38, in 78..90 -> "yesil"
in 39..51, in 91..103 -> "mavi"
else -> ""
}
fun getNumValue(i: Int) = when (i) {
in 0..1 -> -99
in 2..13 -> i - 1
in 13..25 -> (i - 1) - 13
in 26..38 -> (i - 1) - 26
in 39..51 -> (i - 1) - 39
in 52..64 -> (i - 1) - 52
in 65..77 -> (i - 1) - 65
in 78..90 -> (i - 1) - 78
in 91..103 -> (i - 1) - 91
else -> -99
}
fun getDrawableID(i: Int) = when (i) {
in 0..1 -> drawablesIDs[0]
in 2..13, in 13..25, in 26..38, in 39..51 -> drawablesIDs[i - 1]
in 52..64 -> drawablesIDs[(i - 1) - 52]
in 65..77 -> drawablesIDs[i - 1 - 65 + 13]
in 78..90 -> drawablesIDs[i - 1 - 78 + 26]
in 91..103 -> drawablesIDs[i - 1 - 91 + 39]
else -> -99
}
val myItemClassArray = Array(104) {
Item(getColor(it), getNumValue(it), getDrawableID(it))
}
Maybe there is some mistakes in the different ranges.
The main advantages are :
each mapping is testable independently
no mutability

Related

Kotlin multiple when statement

I am learning to build a simple android app with android studio and i created a function to find the id of some values. While writing this function I thought using when statement (Kotlin) but a sadly had to repeat it. Is there a way to assign the result of a when statement to multiple variables at the same time? In other language I would just have returned a list which I would have disassembled but I can't find a way to do it in Kotlin. It's not really big problem but I like optimizing my code.
// my Kotlin function
// setting a specific state
private fun setState(num: Int) {
Log.v(TAG, num.toString())
// get the correct image id
val imageId: Int? = when (num) {
0 -> R.drawable.lemon_restart
1 -> R.drawable.lemon_tree
2 -> R.drawable.lemon_squeeze
3 -> R.drawable.lemon_drink
else -> null
}
// get the correct text to show
val txtId: Int? = when (num) {
0 -> R.string.txt_state_0
1 -> R.string.txt_state_1
2 -> R.string.txt_state_2
3 -> R.string.txt_state_3
else -> null
}
// get the correct content description for accessibility
val contentDescriptionId: Int? = when (num) {
0 -> R.string.lemon_restart_description
1 -> R.string.lemon_tree_description
2 -> R.string.lemon_squeeze_description
3 -> R.string.lemon_drink_description
else -> null
}
// setting the new stuff
val imView: ImageView = findViewById(R.id.imageState)
val txtView: TextView = findViewById(R.id.textOrder)
txtView.text = getString(txtId!!)
imView.setImageResource(imageId!!)
imView.contentDescription = getString(contentDescriptionId!!)
}
feel free to optimize it as much as possible
You can return Triple or your own data class from when, and then destructure it:
val (imageId, txtId, contentDescriptionId) = when (num) {
0 -> Triple(R.drawable.lemon_restart, R.string.txt_state_0, R.string.lemon_restart_description)
...
else -> Triple(null, null, null)
}
Since every field is constant and states are fixed. you can make the states as constant. to decouple code little bit you can create a separate class to return the values for particular state. below is an Example :
class StateHandle private constructor(imageId: Int?, txtId: Int?, contentDescriptionId: Int?) {
companion object {
private val imageIds = arrayOf(
R.drawable.lemon_restart,
R.drawable.lemon_tree,
R.drawable.lemon_squeeze,
R.drawable.lemon_drink
)
private val txtIds = arrayOf(
R.string.txt_state_0,
R.string.txt_state_1,
R.string.txt_state_2,
R.string.txt_state_3
)
private val contentIds = arrayOf(
R.string.lemon_restart_description,
R.string.lemon_tree_description,
R.string.lemon_squeeze_description,
R.string.lemon_drink_description
)
#JvmStatic
fun getStateFor(num: Int): StateHandle {
return StateHandle(
imageIds.getOrNull(num), txtIds.getOrNull(num),
imageIds.getOrNull(num)
)
}
}
}
Its not perfect but it is a bit more reusable . just call #getStateFor and use the StateHandle object .

Not getting random DIE results, all 6 are showing same image and same rolled number

I need to display 5 random die results, what am I doing wrong that they are all resulting in the same number and image? IE. Roll a 5, they all show 5 and the 5 image shows up when they all need to be random.
val iv1 = findViewById(R.id.iv1) as ImageView
val iv2 = findViewById(R.id.iv2) as ImageView
val iv3 = findViewById(R.id.iv3) as ImageView
val iv4 = findViewById(R.id.iv4) as ImageView
val iv5 = findViewById(R.id.iv5) as ImageView
val btnRoll = findViewById<Button>(R.id.btnRoll)
btnRoll.setOnClickListener {
val randomInt = Random().nextInt(5) + 1
val drawableResource = when (randomInt) {
1 -> R.drawable.die1
2 -> R.drawable.die2
3 -> R.drawable.die3
4 -> R.drawable.die4
5 -> R.drawable.die5
else -> R.drawable.die6
}
iv1.setImageResource(drawableResource)
iv2.setImageResource(drawableResource)
iv3.setImageResource(drawableResource)
iv4.setImageResource(drawableResource)
iv5.setImageResource(drawableResource)
How to do it with minimal changes to your code: Put your views in a list so you can loop through them so each one gets a random value:
btnRoll.setOnClickListener {
val imageViews = listOf(iv1, iv2, iv3, iv4, iv5)
for (imageView in imageViews) {
val randomInt = Random().nextInt(5) + 1
val drawableResource = when (randomInt) {
1 -> R.drawable.die1
2 -> R.drawable.die2
3 -> R.drawable.die3
4 -> R.drawable.die4
5 -> R.drawable.die5
else -> R.drawable.die6
}
imageView.setImageResource(drawableResource)
}
}
But to do this with less code duplication, I would initialize all your views in a list to begin with. Also, you can eliminate the when statement by listing your drawables and calling random() on the list directly:
val imageViews = listOf(R.id.iv1, R.id.iv2, R.id.iv3, R.id.iv4, R.id.iv5)
.map { findViewById<ImageView>(it) }
val drawables = listOf(
R.drawable.die1,
R.drawable.die2,
R.drawable.die3,
R.drawable.die4,
R.drawable.die5,
R.drawable.die6
)
val btnRoll = findViewById<Button>(R.id.btnRoll)
btnRoll.setOnClickListener {
for (imageView in imageViews) {
imageView.setImageResource(drawables.random())
}
}
I think before you could solve this \you could have think of it as algorithm get n distinct random numbers check my solution for this:
val views = listOf<ImageView>(
findViewById(R.id.iv1) as ImageView,
findViewById(R.id.iv2) as ImageView,
findViewById(R.id.iv3) as ImageView,
findViewById(R.id.iv4) as ImageView,
findViewById(R.id.iv5) as ImageView,
)
btnRoll.setOnClickListener {
val s: MutableSet<Int> = mutableSetOf()
while (s.size < views.size) { s.add((views.indices).random()) }
s.forEachIndexed { index, value ->
val drawableResource = when (value + 1) {
1 -> R.drawable.die1
2 -> R.drawable.die2
3 -> R.drawable.die3
4 -> R.drawable.die4
5 -> R.drawable.die5
else -> R.drawable.die6
}
views[index].setImageResource(drawableResource)
}
}

Android Multi-row summation: Request for code shortening

I have a table with fifteen rows. Each row have three columns and a total column. I want to get the total per row, the grand total, and the overall average.
The user may not enter data for all rows, and the user may skip a row.
So the code checks if the user have entered data in one of three fields of each row.
If the row is blank, ignore it.
If some of the fields are filled-up, tell the user to fill up the rest of the row.
If all the fields in a row is filled up, sum all its fields and increment the divider.
I have only pasted the codes for Rows 1 & 2 for brevity, but it shows the gist of what I'm trying to achieve:
The code:
var a1 = 0
var a2 = 0
var total = 0
var divider = 0
// Row 1
if (b1p1.text.isNotEmpty() or b2p1.text.isNotEmpty() or b3p1.text.isNotEmpty()) {
var y = 0
listOf(b1p1, b2p1, b3p1).forEach {
if (it.text.isEmpty()) {
it.error = "Fill up empty fields!"
y = 1
}
}
if (y == 0) {
divider++
listOf(b1p1, b2p1, b3p1).forEach {
a1 += it.text.toString().toInt()
}
total1.text = a1.toString()
total += a1
e2 = 1
} else {
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show()
}
}
// Row 2
if (b1p2.text.isNotEmpty() or b2p2.text.isNotEmpty() or b3p2.text.isNotEmpty()) {
var y = 0
listOf(b1p2, b2p2, b3p2).forEach {
if (it.text.isEmpty()) {
it.error = "Fill up empty fields!"
y = 1
}
}
if (y == 0) {
divider++
listOf(b1p2, b2p2, b3p2).forEach {
a2 += it.text.toString().toInt()
}
total2.text = a2.toString()
total += a2
} else {
Toast.makeText(activity, "Error", Toast.LENGTH_SHORT).show()
}
}
if (e2 == 1) {
grandTotalTextView.text = total.toString()
average = total.toDouble()/divider
val decimalFormatter = DecimalFormat("#,###.##")
averageTextView.text = decimalFormatter.format(average).toString()
cyeSingleton.anct3b = decimalFormatter.format(average).toString()
} else {
Toast.makeText(activity, "Error 2", Toast.LENGTH_SHORT).show()
}
The table:
This is the best I could come up with. Should there be no other suggestion, I will settle for this.
Thanks in advance!
**EDIT: Thanks to ** https://stackoverflow.com/users/3736955/jemshit-iskenderov
data class TotalResult(val divider:Int, val allTotal:Int, val showError:Boolean)
private fun calculateTotalResult(allTextViews:List<List<TextView>>, totalTextViews:List<TextView>): TotalResult {
var divider = 0
var allTotal = 0
var showError=false
allTextViews.forEachIndexed{index, rowTextViews->
val rowResult = calculateRowResult(rowTextViews as List<EditText>, totalTextViews[index])
if(!rowResult.ignoreRow){
if(rowResult.allFieldsFilled){
divider+=1
allTotal+=rowResult.rowTotal
}else{
showError = true
}
}
}
Toast.makeText(
activity,
"$divider, $allTotal, $showError", Toast.LENGTH_SHORT)
.show()
return TotalResult(divider, allTotal, showError)
}
data class RowResult(val ignoreRow:Boolean, val allFieldsFilled:Boolean, val rowTotal:Int)
private fun calculateRowResult(rowTextViews:List<EditText>, totalTextView:TextView): RowResult {
val ignore = rowTextViews.filter{it.text.isBlank()}.count() == rowTextViews.size
if(ignore)
return RowResult(true, false, 0)
var emptyFieldCount = 0
var total = 0
rowTextViews.forEach {textView ->
if (textView.text.isEmpty()) {
textView.error = "Fill up empty fields!"
emptyFieldCount +=1
}else{
val fieldValue:Int? = textView.text.toString().toIntOrNull() // or toIntOrElse{0}
if(fieldValue!=null) total+=fieldValue
}
}
if(emptyFieldCount==0)
totalTextView.text = total.toString()
return RowResult(false, emptyFieldCount==0, total)
}
fun main(){
val totalResult = calculateTotalResult(
allTextViews = listOf(
listOf(t11,t12,t13),
listOf(t21,t22,t23)
),
totalTextViews = listOf(totalView1, totalView2)
)
// single Toast error
if(totalResult.showError){
// showToast(error)
}
// use totalResult.divider, totalResult.allTotal
}
data class TotalResult(val divider:Int, val allTotal:Int, val showError:Boolean)
fun calculateTotalResult(allTextViews:List<List<TextView>>, totalTextViews:List<TextView>){
var divider = 0
var allTotal = 0
var showError=false
allTextViews.forEachIndexed{index, rowTextViews->
val rowResult = calculateRowResult(rowTextViews, totalTextViews[index])
if(!rowResult.ignore){
if(rowResult.allFieldsFilled){
divider+=1
allTotal+=rowResult.rowTotal
}else{
showError = true
}
}
}
return TotalResult(divider, allTotal, showError)
}
data class RowResult(val ignoreRow:Boolean, val allFieldsFilled:Boolean, val rowTotal:Int)
fun calculateRowResult(rowTextViews:List<TextView>, totalTextView:TextView): RowResult {
val ignore = rowTextViews.filter{it.isBlank()}.count() == rowTextViews.size
if(ignore)
return RowResult(true, false, 0)
var emptyFieldCount = 0
var total = 0
rowTextViews.forEach {textView ->
if (textView.text.isEmpty()) {
textView.error = "Fill up empty fields!"
emptyFieldCount +=1
}else{
val fieldValue:Int? = textView.text.toString().toIntOrNull() // or toIntOrElse{0}
if(fieldValue!=null) total+=fieldValue
}
}
if(emptyFieldCount==0)
totalTextView.text = total.toString()
return RowResult(false, emptyFieldCount==0, total)
}
Extracted calculateTotalResult() and calculateRowResult() so multiple rows and columns do not need to repeat same code.
calculateRowResult() processes singlet row of TextViews. I had to iterate rowTextViews twice, one to calculate ignore, the other to show error on TextView if not ignore. We don't show Toast Error here yet.
calculateTotalResult() iterates through all rows and gets total result. We show only one Toast Error (if required) after this step.
Code is pseudo-code, not tested.

Getting Issue in xAxis.setValueFormatter with Dynamic value :

I am getting some issue Bar Graph with Dynamic values in X-Axis values setValueFormatter:
I checked with a list view, recycler view and view inflation but always getting issues in the values in X-Axis Formatter that it doesn't work with value when list size is 3 or less than 3.
With View Inflation:
Requirement: I want to set the values in a graph with a set of 8. Like, If my list size is 14,
So the graph view inflates 2 times like:
If my list size is 10, it will inflate 2 times, first with 8 values of bar graph and the second graph only with 2 values. It works for the same when the list size is 9, 8 values for the first graph and 1 value for the second graph.
But the issue is that when the remaining value for the last graph is less than 4 like:
when the list size is 11, the remaining value is 3
when the list size is 25, the remaining value is 1 for the fourth graph
It gives the repeated or duplicated value in the x Axis like this:
Here is the issue:
xAxis.setValueFormatter(object : IAxisValueFormatter {
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
var size : String = ""
try {
if(value>=0&&!mMonths[value.toInt()/10 % mMonths.size].equals("")&&value<mMonths.size*10) {
size = mMonths[0 / 10 % mMonths.size]
}
}catch (e : IndexOutOfBoundsException){
xAxis.isGranularityEnabled=false
}
return size
}
})
Note: This will work fine when mMonths list size is greater than 3 as you can see in the first screenshot but it gives issues for list size 1, 2 or 3.
Source code:
private fun setBarChart(mList:ArrayList) {
var calender_size: Float = 0.0f
if(mList.
size>0){
if(mList.size>8){
if(mList.size/8==0){
calender_size = (mList.size / 8).toFloat()
}else{
calender_size = (mList.size / 8).toFloat() + 1
}
}else{
calender_size = 1f
}
}
var section_variable: Int = 0
var tillvalue: Int = 0
var list_size: Int = 1
allGraphs.clear()
multiplegraphviewtmp.removeAllViews()
for (i in 0 until Math.round(calender_size)) {
val newLayout = layoutInflater.inflate(R.layout.new_functionalgraph, null, false)
multiplegraphviewtmp.addView(newLayout)
allGraphs.add(newLayout)
newLayout.tv_categoryname.setText(mList[0].description)
val entriesnew = ArrayList<BarEntry>()
entriesnew.clear()
var mMonths : ArrayList<String> = ArrayList()
mMonths.clear()
if(mList.size>8){
if (i > 0) {
if (mList.size / 8 == 0) {
list_size = (i + 1) * 8
} else {
val temp = mList.size % 8
if ((i + 1) * 8 < mList.size) {
list_size = (i + 1) * 8
} else {
// section_variable = section_variable + temp
list_size = list_size + temp
}
}
} else {
list_size = 8
}
for (j in section_variable until list_size) {
entriesnew.add(BarEntry((tillvalue * 10).toFloat(), mList[j].percentage.toFloat()))
mMonths.add(mList[j].itemName)
section_variable++
tillvalue++
}
tillvalue = 0
}else{
list_size=1
for (j in 0 until mList.size) {
entriesnew.add(BarEntry((tillvalue * 10).toFloat(), mList[j].percentage.toFloat()))
mMonths.add(mList[j].itemName)
//section_variable++
tillvalue++
}
tillvalue = 0
}
newLayout.barChartmore.legend.isEnabled = false
newLayout.barChartmore.description.isEnabled = false
var leftAxisfornewgraphs = newLayout.barChartmore.getAxisLeft()
leftAxisfornewgraphs.setAxisMaxValue(100f)
leftAxisfornewgraphs.setAxisMinValue(0f)
leftAxisfornewgraphs.setStartAtZero(true)
leftAxisfornewgraphs.setAxisLineWidth(0f)
leftAxisfornewgraphs.setLabelCount(11, true)
leftAxisfornewgraphs.setDrawGridLines(true)
leftAxisfornewgraphs.axisLineColor = activity!!.resources.getColor(R.color.graph_textColor)
leftAxisfornewgraphs.textColor = activity!!.resources.getColor(R.color.graph_textColor)
leftAxisfornewgraphs.typeface = Typeface.DEFAULT_BOLD
leftAxisfornewgraphs.textSize = 12f
leftAxisfornewgraphs.gridColor = activity!!.resources.getColor(R.color.view)
leftAxisfornewgraphs.axisLineColor = activity!!.resources.getColor(R.color.view)
// leftAxisfornewgraphs.setValueFormatter(MyYAxisValueFormatter()) //////////to set labels in %
//////////////////to change Right line/////////////////
var rightAxis = newLayout.barChartmore.axisRight
rightAxis.setDrawGridLines(false)
rightAxis.setDrawLabels(false)
rightAxis.setLabelCount(40, true)
rightAxis.axisLineColor = activity!!.resources.getColor(R.color.view)
var xAxis = newLayout.barChartmore.getXAxis()
xAxis.textSize = 9f
xAxis.setPosition(XAxis.XAxisPosition.BOTTOM)
xAxis.setLabelRotationAngle(-90f)
xAxis.textColor = activity!!.resources.getColor(R.color.graph_textColor)
xAxis.typeface = Typeface.DEFAULT_BOLD
xAxis.gridColor = activity!!.resources.getColor(R.color.view)
xAxis.axisLineColor = activity!!.resources.getColor(R.color.view)
xAxis.granularity=1f
newLayout.barChartmore.setPinchZoom(false)
newLayout.barChartmore.getLegend().setWordWrapEnabled(true)
newLayout.barChartmore.setScaleEnabled(false)
newLayout.barChartmore.isDoubleTapToZoomEnabled=false
val labels = ArrayList<String>()
labels.clear()
for (i in 0 until mMonths.size){
labels.add("18-Jan")
}
xAxis.setValueFormatter(object : IAxisValueFormatter {
override fun getFormattedValue(value: Float, axis: AxisBase?): String {
var size : String = ""
try {
if(value>=0&&!mMonths[value.toInt()/10 % mMonths.size].equals("")&&value<mMonths.size*10) {
size = mMonths[0 / 10 % mMonths.size]
mTotalvalues++
}
}catch (e : IndexOutOfBoundsException){
xAxis.isGranularityEnabled=false
}
return size
}
})
xAxis.spaceMin = 6f
xAxis.spaceMax = 6f
val barDataSet = BarDataSet(entriesnew, "Cells")
barDataSet.setDrawValues(false)
val list: ArrayList<Int> = ArrayList<Int>()
list.clear()
list.add(activity!!.resources.getColor(R.color.graph_skyblue))
list.add(activity!!.resources.getColor(R.color.graph_orange))
list.add(activity!!.resources.getColor(R.color.graph_navyBlue))
barDataSet.setColors(list)
val data = BarData(barDataSet);
if(mMonths.size<2){
data.barWidth= 1f
}else{
data.barWidth= 5f
}
newLayout.barChartmore.data = data
newLayout.barChartmore.invalidate()
newLayout.export_single.setOnClickListener(View.OnClickListener {
Commonclass.createPdf(activity, newLayout.barChartmore.chartBitmap)
})
//newLayout.barChartmore.clear()
}
}
Same Issue getting with recycler view and Listview. please help:
I am getting some issue Bar Graph with Dynamic values in XAxis values setValueFormatter

How can i modify elements of a List in a for loop

I want to compare version names but to do so I have to conform them to the same standard, i.e. Major.Minor.Patch (1.3.21 for example).
Problem is I can't change the element i'm iterating over.
I store the versions as List and then all versions in another list that I pass as a variable to the following function.
var version_a = listOf(1)
var version_b = listOf(1, 2)
var version_c = listOf(1, 2, 3)
val versions = listOf(version_a, version_b, version_c)
adjustLengthExample(versions)
fun adjustLengthExample(versions: List<List<Int>>){
for((index, version) in versions.withIndex()){
while(version.size < 3){
version = mutableListOf().addAll(version).add(0) //using element: Error Val cannot be reassigned
versions[index] = mutableListOf().addAll(version).add(0) //using indexed position: Error: No set method providing array access
}
}
}
versions.foreach(Log.d(TAG, it.toString())) //Expected output: [1,0,0][1,2,0][1,2,3]
How can I access version_a/b/c and set/change it's value?
Instead of
var version_a = listOf(1)
use
val version_a = mutableListOf(1)
then in the whileloop just change the list`s content
while(version.size < 3) {
version.add(0)
// or
versions[index].add(0)
}
Here is the full example:
fun main(args: Array<String>) {
fun adjustLengthExample(versions: List<MutableList<Int>>){
for((index, version) in versions.withIndex()){
while(version.size < 3){
version.add(0)
// or
//versions[index].add(0)
}
}
}
val version_a = mutableListOf(1)
val version_b = mutableListOf(1, 2)
val version_c = mutableListOf(1, 2, 3)
val versions = listOf(version_a, version_b, version_c)
adjustLengthExample(versions)
versions.forEach { println(it) }
}
This outputs:
[1, 0, 0]
[1, 2, 0]
[1, 2, 3]
To do the same with immutable lists new lists have to be created and adjustLengthExample has to return the new list. Like this:
fun main(args: Array<String>) {
fun adjustLengthExample(versions: List<List<Int>>): List<List<Int>> {
var result: List<List<Int>> = listOf()
for ((index, version) in versions.withIndex()) {
var newVersion: List<Int> = version
while (newVersion.size < 3) {
newVersion += 0
}
result += listOf(newVersion)
}
return result
}
val version_a = listOf(1)
val version_b = listOf(1, 2)
val version_c = listOf(1, 2, 3)
var versions = listOf(version_a, version_b, version_c)
versions = adjustLengthExample(versions)
versions.forEach { println(it) }
}
There's a much easier way to achieve that:
val versions = listOf(listOf(1), listOf(1, 2), listOf(1, 2, 3))
val result = versions.map {
(it + listOf(0, 0, 0)).subList(0, 3)
}
println(result)
Output:
[[1, 0, 0], [1, 2, 0], [1, 2, 3]]

Categories

Resources