Merge properties of a list to another based on properties objects - kotlin

I got 2 lists with x objects inside , for example:
data class Model(
var token: String = "",
var id: String = "",
var name: String = "",
var image: Int = 0,
)
array is initialized and filled, the other list has x objects also that contains the objects of the first list but with different values in their properties!
what I want to do is to change the properties of the first array by the second one if they got the same object.name
var arr1 = ArrayList<Model>() // locale
var arr2 = ArrayList<Model>() // from db
the first array I got for example
[Model(name = "David", token = "" , image = 0)]
the second array I got
[Model(name = "David", token = "1asd5asdd851", image = 1)]
How do I make the first array take the missing token?
I tried with .filter{} and with .map{}. groupBy {} for hours because Name is the only properties that are the same but I'm more and more confused.

We can first group the second array by name using associateBy() and then iterate over first array and reassign properties:
val arr2ByName = arr2.associateBy { it.name }
arr1.forEach { item1 ->
arr2ByName[item1.name]?.let { item2 ->
item1.token = item2.token
item1.image = item2.image
}
}
Alternatively, if you don't need to modify items in arr1, but create another array and you can use items from both arr1 and arr2, then it will be much easier:
val arr3 = arr1.map { arr2ByName[it.name] ?: it }

One possible way would be to use fold() as follows:
fun main(args: Array<String>) {
val arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
val mergedModels = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(mergedModels)
}
If you want to reuse arr1 variable then you can do the following (but I would still use the previous option):
fun main(args: Array<String>) {
var arr1 = listOf(Model(name = "David", token = "" , image = 0))
val arr2 = listOf(Model(name = "David", token = "1asd5asdd851", image = 1))
arr1 = arr2.fold(arr1) { localModels, dbModel ->
localModels.map { localModel ->
if (localModel.name == dbModel.name) localModel.copy(token = dbModel.token, image = dbModel.image)
else localModel
}
}
println(arr1)
}

Related

How to set Xaxis and Yaxis using data class using kotlin in MpAndroid bar chart

Halo i am trying to create barchart using MPAndroid Library but icant how to use it when i send json from php
echo json_encode($output);
and the output contain 2 data that is hari and total_jual
$rowdata[]=array('hari'=>$row['hari'],
'total_jual'=>$row['total_jual']);
in android studio i am using volley to catch jason
for(i in 0 until arr.length()){
val obj = arr.getJSONObject(i)
dataListPenjualan.add(
ClassPenjualan(
obj.getString("hari").toString(),
obj.getString("total_jual").toString()
)
)
val entries = ArrayList<BarEntry>()
val barDataSet = BarDataSet(entries, "Cells")
val labels = ArrayList<String>()
labels.add(dataListPenjualan[i].hari)
//barDataSet.setColors(ColorTemplate.COLORFUL_COLORS)
barDataSet.color = resources.getColor(R.color.black)
chartPemasukan.animateY(5000)
}
the data i catch using volley i send it into class
this is my class
data class ClassPenjualan (val hari:String,
val totalPenjualan:String)
how can i create barchart using data i catch from php. I already try to search but many explanation is in java.
this is what i try
val entries = ArrayList<BarEntry>()
entries.add(BarEntry(dataListPenjualan[i].hari.toFloat(), i))
val barDataSet = BarDataSet(entries, "Cells")
val labels = ArrayList<String>()
labels.add(dataListPenjualan[i].hari)
val data = BarData(labels, barDataSet)
chartPemasukan.data = data // set the data and list of lables into chart
chartPemasukan.setDescription("Set Bar Chart Description") // set the description
//barDataSet.setColors(ColorTemplate.COLORFUL_COLORS)
barDataSet.color = resources.getColor(R.color.black)
chartPemasukan.animateY(5000)
Your code entries.add(BarEntry(dataListPenjualan[i].hari.toFloat(), i)) is wrong.
just try entries.add(BarEntry(i,dataListPenjualan[i].hari.toFloat()))
below code is my demo
val values = ArrayList<BarEntry>()
var i = 0
while (i < xValueCount) {
val yValue = (Math.random() * (100)).toFloat()
values.add(BarEntry(i.toFloat(), yValue))
i++
}
val set1: BarDataSet
if (chart.data != null &&
chart.data.dataSetCount > 0) {
set1 = chart.data.getDataSetByIndex(0) as BarDataSet
set1.values = values
chart.data.notifyDataChanged()
chart.notifyDataSetChanged()
} else {
set1 = BarDataSet(values, "speed")
//绘制图标
set1.setDrawIcons(false)
//绘制数值
set1.setDrawValues(false)
set1.color = ContextCompat.getColor(mContext, getBarHighColorByDataType(false))
set1.highLightColor = ContextCompat.getColor(mContext, getBarHighColorByDataType(true))
set1.highLightAlpha = 255
val dataSets = ArrayList<IBarDataSet>()
dataSets.add(set1)
val data = BarData(dataSets)
data.setValueTextSize(10f)
//barWith = 柱宽度/(柱宽度+旁边一处空白宽度)
data.barWidth = when (dataType) {
0 -> 0.37f
1 -> 0.52f
2 -> 0.3f
else -> 0.43f
}
chart.data = data
}

How do I assign a value to an empty string in my code to prevent NumberFormatException

I'm having a NumberFormatException which is likely due passing an empty string to product_quantity in the product and cart data class. I'm having difficulty assigning value to the product_quantity in my code before parsing it toInt()
E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.hardextech.store, PID: 22948
java.lang.NumberFormatException: For input string: ""
at java.lang.Integer.parseInt(Integer.java:627)
at java.lang.Integer.parseInt(Integer.java:650)
at com.hardextech.store.ui.activities.ui.activities.CartListActivity.successfullyGetTheCartItemList(CartListActivity.kt:90)
at com.hardextech.store.firestore.FirestoreClass.getCartList$lambda-28(FirestoreClass.kt:493)
at com.hardextech.store.firestore.FirestoreClass.$r8$lambda$Uc6EU1OaDQc7HeKgs7cM5uEsC2A(Unknown Source:0)
at com.hardextech.store.firestore.FirestoreClass$$ExternalSyntheticLambda12.onSuccess(Unknown Source:4)
at com.google.android.gms.tasks.zzn.run(com.google.android.gms:play-services-tasks##17.2.0:4)
at android.os.Handler.handleCallback(Handler.java:873)
at android.os.Handler.dispatchMessage(Handler.java:99)
at android.os.Looper.loop(Looper.java:193)
at android.app.ActivityThread.main(ActivityThread.java:6819)
at java.lang.reflect.Method.invoke(Native Method)
at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:497)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:912)
This is the successfullyGetCartTheCartItemList method referenced from the debugging console
fun successfullyGetTheCartItemList(listOfItemInTheCart: ArrayList<Cart>){
dismissProgressDialogue()
// checking for the product list in the stock-- determining if the product is available in the stock
for (everyProductInTheProductList in mProductList){
for (everyProductInTheCart in listOfItemInTheCart){
if (everyProductInTheProductList.product_id == everyProductInTheCart.product_id){
everyProductInTheCart.product_quantity = everyProductInTheProductList.product_quantity
// if there are no products in the stock
if (everyProductInTheProductList.product_quantity.toInt() == 0){
everyProductInTheCart.cart_quantity = everyProductInTheProductList.product_quantity
}
}
}
}
// initializing the mCartDataClassDetails
mCartDataClassDetails = listOfItemInTheCart
// checking for the product list in the cart
if (mCartDataClassDetails.size >0){
rv_cart_item_list.visibility = View.VISIBLE
ll_check_out.visibility = View.VISIBLE
tv_no_cart_item_found.visibility = View.GONE
rv_cart_item_list.layoutManager = LinearLayoutManager(this)
rv_cart_item_list.setHasFixedSize(true)
// create an adapter variable for the recycler view
val cartListAdapter = CartItemListAdapter(this, listOfItemInTheCart)
// pass the adapter to the recyclerview
rv_cart_item_list.adapter = cartListAdapter
// assign double to the sub-total in the itemListCart
var subTotal: Double = 0.0
// run through all product in the list
for (everyItemInTheCart in mCartDataClassDetails){
// checking for the available quantity of product
val availableProductQuantity = everyItemInTheCart.product_quantity.toInt()
if (availableProductQuantity > 0){
Log.i("Cart Title", everyItemInTheCart.product_title)
// convert the price to Double
val price = everyItemInTheCart.product_price.toDouble()
// convert the quantity to Int
val quantity = everyItemInTheCart.cart_quantity.toInt()
// calculate the sub-total cost
subTotal+=(price*quantity)
}
}
// assign the value of the sub total for each product sales
tv_product_subTotal.text = "NGN $subTotal"
// assigning the delivery cost for each product sales
// TODO: Seek for API to calculate the delivery cost for each product and/or write the code criteria for calculating it
tv_delivery_cost.text = (subTotal*0.05).toString()
if (subTotal > 0){
ll_check_out.visibility = View.VISIBLE
// TODO: Change the logic for the delivery cost
val totalProductCost = subTotal + (subTotal*0.05)
tv_total_product_cost.text = "NGN $totalProductCost"
} else{
ll_check_out.visibility = View.GONE
}
} else{
rv_cart_item_list.visibility = View.GONE
ll_check_out.visibility = View.GONE
tv_no_cart_item_found.visibility = View.VISIBLE
}
}
This is method from the Firestore class
fun getCartList(activity: Activity){
// the method for downloading the cart item list
mFireStore.collection(Constants.CART_ITEMS_COLLECTION)
// get the cart items for the logged in user
.whereEqualTo(Constants.USER_ID, getCurrentUserID())
.get()
.addOnSuccessListener { document->
Log.i(activity.javaClass.simpleName, document.documents.toString())
// get the list of the cart items--- number of products in the cart
val listOfCartItems: ArrayList<Cart> = ArrayList()
// run through each of the document(FireStore document field) in the list
for (loopingThroughCartItems in document.documents){
// converting the products in the cart to an object and surround with null check
val cartItemListObject = loopingThroughCartItems.toObject(Cart::class.java)!!
cartItemListObject.id= loopingThroughCartItems.id
// add the result of the loop to the cart item arrayList
listOfCartItems.add(cartItemListObject)
}
when(activity){
is CartListActivity->{
activity.successfullyGetTheCartItemList(listOfCartItems)
}
}
}.addOnFailureListener {e->
Log.e(activity.javaClass.simpleName, " Error downloading products in the cart", e)
when(activity){
is CartListActivity->{
activity.dismissProgressDialogue()
}
}
}
}
This is Product Data class
#Parcelize
data class Product(
val user_id: String = "",
var id: String = "",
val product_image: String = "",
val product_title: String = "",
val product_price: String = "",
val product_description: String = "",
val product_quantity: String = "",
val user_name: String = "",
var product_id:String =""
): Parcelable
This is the cart data class
#kotlinx.parcelize.Parcelize
data class Cart(
val user_id: String = "",
val product_id: String = "",
val product_title: String = "",
val product_image: String = "",
val product_price: String = "",
var cart_quantity: String = "",
var product_quantity: String ="",
var id: String = ""
): Parcelable
You can use toIntOrNull, which returns parsed Int or null when failed to parse. Then, use let with ?., like this:
string.toIntOrNull()?.let { parsedInt ->
// Your code here
}

How to try every possible permutation in Kotlin

fun main () {
var integers = mutableListOf(0)
for (x in 1..9) {
integers.add(x)
}
//for or while could be used in this instance
var lowerCase = listOf("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
var upperCase = listOf('A','B','C','D','E','F','G','H','I','J','K','L','M','N','O','P','Q','R','S','T','U','V','W','X','Y','Z')
println(integers)
println(lowerCase)
println(upperCase)
//Note that for the actual program, it is also vital that I use potential punctuation
val passwordGeneratorKey1 = Math.random()*999
val passwordGeneratorKey2 = passwordGeneratorKey1.toInt()
var passwordGeneratorL1 = lowerCase[(Math.random()*lowerCase.size).toInt()]
var passwordGeneratorL2 = lowerCase[(Math.random()*lowerCase.size).toInt()]
var passwordGeneratorL3 = lowerCase[(Math.random()*lowerCase.size).toInt()]
var passwordGeneratorU1 = upperCase[(Math.random()*upperCase.size).toInt()]
var passwordGeneratorU2 = upperCase[(Math.random()*upperCase.size).toInt()]
var passwordGeneratorU3 = upperCase[(Math.random()*upperCase.size).toInt()]
val password = passwordGeneratorKey2.toString()+passwordGeneratorL1+passwordGeneratorL2+passwordGeneratorL3+passwordGeneratorU1+passwordGeneratorU2+passwordGeneratorU3
println(password)
//No, this isn't random, but it's pretty close to it
//How do I now run through every possible combination of the lists //lowerCase, integers, and upperCase?
}
How do I run through every possible permutation to eventually solve for the randomly generated password? This is in Kotlin.
I think you should append all the lists together and then draw from it by random index, this way you ensure that position of numbers, lower cases and uppercases is random too. Also you don't need to write all the characters, you can use Range which generates them for you.
fun main() {
val allChars = mutableListOf<Any>().apply {
addAll(0..9) // creates range from 0 to 9 and adds it to a list
addAll('a'..'z') // creates range from a to z and adds it to a list
addAll('A'..'Z') // creates range from A to Z and adds it to a list
}
val passwordLength = 9
val password = StringBuilder().apply {
for (i in 0 until passwordLength) {
val randomCharIndex =
Random.nextInt(allChars.lastIndex) // generate random index from 0 to lastIndex of list
val randomChar = allChars[randomCharIndex] // select character from list
append(randomChar) // append char to password string builder
}
}.toString()
println(password)
}
Even shorter solution can be achieved using list methods
fun main() {
val password = mutableListOf<Any>()
.apply {
addAll(0..9) // creates range from 0 to 9 and adds it to a list
addAll('a'..'z') // creates range from a to z and adds it to a list
addAll('A'..'Z') // creates range from A to Z and adds it to a list
}
.shuffled() // shuffle the list
.take(9) // take first 9 elements from list
.joinToString("") // join them to string
println(password)
}
As others pointed out there are less painful ways to generate the initial password in the format of: 1 to 3 digits followed by 3 lowercase characters followed by 3 uppercase characters.
To brute force this password, you will need to consider all 3-permutations of "a..z" and all 3-permitations of "A..Z". In both cases the number of such 3-permutations is 15600 = 26! / (26-3)!. In worst case you will have to examine 1000 * 15600 * 15600 combination, half of this on the average.
Probably doable in a few hours with the code below:
import kotlin.random.Random
import kotlin.system.exitProcess
val lowercaseList = ('a'..'z').toList()
val uppercaseList = ('A'..'Z').toList()
val lowercase = lowercaseList.joinToString(separator = "")
val uppercase = uppercaseList.joinToString(separator = "")
fun genPassword(): String {
val lowercase = lowercaseList.shuffled().take(3)
val uppercase = uppercaseList.shuffled().take(3)
return (listOf(Random.nextInt(0, 1000)) + lowercase + uppercase).joinToString(separator = "")
}
/**
* Generate all K-sized permutations of str of length N. The number of such permutations is:
* N! / (N-K)!
*
* For example: perm(2, "abc") = [ab, ac, ba, bc, ca, cb]
*/
fun perm(k: Int, str: String): List<String> {
val nk = str.length - k
fun perm(str: String, accumulate: String): List<String> {
return when (str.length == nk) {
true -> listOf(accumulate)
false -> {
str.flatMapIndexed { i, c ->
perm(str.removeRange(i, i + 1), accumulate + c)
}
}
}
}
return perm(str, "")
}
fun main() {
val password = genPassword().also { println(it) }
val all3LowercasePermutations = perm(3, lowercase).also { println(it) }.also { println(it.size) }
val all3UppercasePermutations = perm(3, uppercase).also { println(it) }.also { println(it.size) }
for (i in 0..999) {
println("trying $i")
for (l in all3LowercasePermutations) {
for (u in all3UppercasePermutations) {
if ("$i$l$u" == password) {
println("found: $i$l$u")
exitProcess(0)
}
}
}
}
}

Compare multiple fields of Object to those in an ArrayList of Objects

I have created a 'SiteObject' which includes the following fields:
data class SiteObject(
//Site entry fields (10 fields)
var siteReference: String = "",
var siteAddress: String = "",
var sitePhoneNumber: String = "",
var siteEmail: String = "",
var invoiceAddress: String = "",
var invoicePhoneNumber: String = "",
var invoiceEmail: String = "",
var website: String = "",
var companyNumber: String = "",
var vatNumber: String = "",
)
I want to filter an ArrayList<SiteObject> (call it allSites) by checking if any of the fields of the objects within the list match those in a specific <SiteObject> (call it currentSite).
So for example, I know how to filter looking at one field:
fun checkIfExistingSite(currentSite: SiteObject) : ArrayList<SiteObject> {
var matchingSites = ArrayList<SiteObject>()
allSites.value?.filter { site ->
site.siteReference.contains(currentSite.siteReference)}?.let { matchingSites.addAll(it)
}
return matchingSites
}
But I am looking for an elegant way to create a list where I compare the matching fields in each of the objects in allSites with the corresponding fields in currentSite..
This will give me a list of sites that may be the same (allowing for differences in the way user inputs data) which I can present to the user to check.
Use equals property of Data Class:
val matchingSites: List<SiteObject> = allSites
.filterNotNull()
.filter { it.equals(currentSite) }
If you are looking for a more loose equlity criteria than the full match of all fields values, I would suggest usage of reflection (note that this approach could have performance penalties):
val memberProperties = SiteObject::class.memberProperties
val minMatchingProperties = 9 //or whatever number that makes sense in you case
val matchingItems = allSites.filter {
memberProperties.atLeast(minMatchingProperties) { property -> property.get(it) == property.get(currentSite) }
}
fun <E> Iterable<E>.atLeast(n: Int, predicate: (E) -> Boolean): Boolean {
val size = count()
return when {
n == 1 -> this.any(predicate)
n == size -> this.all(predicate)
n > size - n + 1 -> this.atLeast(size - n + 1) { !predicate.invoke(it) }
else -> {
var count = 0
for (element in this) {
if (predicate.invoke(element)) count++
if (count >= n) return true
}
return false
}
}
}
you could specify all the fields by which you want to match the currentSite inside the filter predicate:
fun checkIfExistingSite(currentSite: SiteObject) =
allSites.filter {
it.siteAddress == currentSite.siteAddress
|| it.sitePhoneNumber == currentSite.sitePhoneNumber
|| it.siteReference == currentSite.siteReference
}
Long but fast solution because of short circuiting.
If the list is nullable you can transform it to a non nullable list like:
allSites?filter{...}.orEmpty()
// or imho better
allSites.orEmpty().filter{...}

How to get the index of a gson object?

I need to get the index of the array containing the member fileName = "Andres"
data class File(var fileName: String, var _id : String? = null)
data class Files(val files: Array<File>)
val miObjetG = Gson().fromJson(response_files, Files::class.java)
var indice = miObjetG.files.filterIndexed { index, file -> file.fileName == "Andres"}
I think indexOfFirst is what you are looking for:
val index = miObjetG.files.indexOfFirst{ it.fileName == "Andres" }