I have use two different classes:
ListTitle.kt
class ListTitle {
var id: Int? = null
var title: String? = null
constructor(id:Int, title: String) {
this.id = id
this.title = title
}
}
ListDes.kt
class ListDes {
var address: Int? = null
var des: String? = null
constructor(address: Int, des: String) {
this.address = address
this.des = des
}
}
listOfTitle and listDes are ArrayLists:
listOfTitle.add(ListTitle(1, "Hello"))
listOfTitle.add(ListTitle(2, "World"))
listDes.add(ListDes(1, "World Des"))
listDes.add(ListDes(2, "Hello Des"))
I want to assign title of ListTitle to des of ListDes by matching them by id/address for each element of the two lists.
How can I approach this?
You can use zip to merge two lists into one which has Pairs as elements.
val listOfTitle = listOf(ListTitle(1, "Hello"), ListTitle(2, "World"))
val listDes = listOf(ListDes(1, "World Des"), ListDes(2, "Hello Des"))
val pairList = listOfTitle.zip(listDes)
// since an element in the new list is a pair, we can use destructuring declaration
pairList.forEach { (title, des) ->
println("${title.title} ${des.des}")
}
Output:
Hello World Des
World Hello Des
A few notes:
You can write your classes in a shorter form in Kotlin. Just put the properties directly in the argument list of the primary constructor like shown below.
class ListTitle(
var id: Int? = null,
var title: String? = null
)
class ListDes(
var address: Int? = null,
var des: String? = null
)
Don't overuse nullability (using Int? instead of Int for instance). Make properties only nullable if necessary. If you always pass in arguments for the specified properties there is not need for them to be nullable.
Maybe you should choose other names for the classes (without "List" in it) since they are actually elements of a List in your example and not lists themselves.
If you just want to print the values you could do this:
listOfTitle.forEach {
val id = it.id
println(it.title + " " + listDes.filter { it.address == id }[0].des)
}
will print the matching des for each id:
Hello World Des
World Hello Des
The above code is supposed to work when both lists have the same length and there is always a matching des for each id
if you want to create a new list with the matching pairs:
val newList = listOfTitle.map { it ->
val id = it.id
Pair(it.title, listDes.filter { it.address == id }[0].des)
}
newList.forEach { println(it.first + " " + it.second) }
Related
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{...}
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" }
I have an arraylist of event
var approvedEvents = ArrayList<Event>()
the class of Event is like this
class Event() {
var eventID : String = ""
var createdBy: String = "" // uid of user creator
var creatorFullName: String = ""
var creatorIsVerified : Boolean = false
var creatorProfilePictureImagePath = ""
var createdAt : Date = Calendar.getInstance().time
var hasBeenApproved : Boolean = false
var title : String = ""
var speaker : String? = null
var coordinate : GeoPoint = City.defaultCityCoordinate
var address : String = ""
var city : String = ""
var venue : String = ""
}
so I want to find an index in approvedEvents arraylist that its eventID match selectedEvent.eventID how to do that in Kotlin ? is there specific method that I can use ?
Use indexOfFirst or indexOfLast to find the index of an item in an ArrayList based on your own criteria like below:
val index = approvedEvents.indexOfFirst{
it.eventID == selectedEvent.eventID
}
First of all, you have to override equals function in your Event class like
------
------
var city : String = ""
var venue : String = ""
override fun equals(other: Any?): Boolean{
if(other is Event){
return eventID.equals(other.eventID)
}
return false;
}
}
Now when you want to search for an Event object with eventId in a list, first create a temporary event object with that eventId which you want to search like
val temp=Event()
temp.eventID="102"
and simply get the index
print(events.indexOf(temp))
data class precioSuper(var producto:String, var precio: Int, val codigoDeBarras:String)
fun main(args: Array<String>) {
//Qué vende o super?
val galletas = precioSuper("galletas", 3, "0001")
val chocolate = precioSuper("chocolate", 5, "0002")
val leite = precioSuper("leite", 2, "0003")
var productos = arrayListOf<String>("galletas", "chocolate", "leite")
var totalProductos = productos.size
var codigoDeBarras2 = for(producto in totalProductos)
}
in the lane of code var codigoDeBarras2 = for(producto in totalProductos) kotlin send me this error: "For-loop range must have an 'iterator()' method"
The error is exactly in "totalProductos" "for(producto in totalProductos)"
The error is that you are assigning the for loop to a variable.
for is not an expression and can't be assigned.
Also the expression producto in totalProductos does not make sense as you treat totalProductos like a Collection but it is only an integer number.
If you want to iterate through the items of the list productos you can do it:
for (producto in productos) {
//..............
}
or
for (i in 0 until totalProductos) {
//..............
}
or
productos.forEach {
}
Assume you are trying to "extract" the producto property of productos list. Then you can try
var codigoDeBarras2 = productos.map { it.producto }
Previously I was using this code:
private val mItems = ArrayList<Int>()
(1..item_count).mapTo(mItems) { it }
/*
mItems will be: "1, 2, 3, 4, 5, ..., item_count"
*/
Now, I am using a class instead of Int, but the class has Int member with name id.
class ModelClass(var id: Int = 0, var status: String = "smth")
So how can I use this method to fill the ArrayList in similar way?
//?
private val mItems = ArrayList<ModelClass>()
(1..item_count).mapTo(mItems) { mItems[position].id = it } // Something like this
//?
From the mapTo documentation:
Applies the given transform function to each element of the original collection and appends the results to the given destination.
Therefore, you just need to return the elements you want:
(1..item_count).mapTo(mItems) { ModelClass(it) }
If you are OK with any MutableList (which is often ArrayList or similar):
val mItems1 = MutableList(item_count) { i -> i }
val mItems2 = MutableList(item_count) { ModelClass(it) }