I create Map <String,List<Object>>
val groupListByUserName = sharedList.groupBy { it -> it.user.displayName }
this function groupBy list by userNAme. Next I create model
data class SharedList(val userName:String,val sharedList: List<MovieMyList>)
I want add data with map to list and I don't konw how. Do you have any idea how make this?
If I understood correctly, you want to convert the Map<String, List<MovieMyList>> into a List<SharedList>, is that it?
val groupListByUserName = sharedList.groupBy { it -> it.user.displayName }
val sharedLists = groupListByUserName.map { (user, movies) -> SharedList(user, movies) }
Note that here, the parentheses in the lambda are important: calling map on a Map will deal with the map's entries, each composed of a key and a value. Using the parentheses performs destructuring on the entry to directly access its key and value.
Related
Bundle.get(key: String) is deprecated:
Use the type-safe specific APIs depending on the type of the item to be retrieved, eg. getString(String).
So how to solve this in this method? Don't think I can use generic T here because the Bundle can contain multiple different types. I feel like I have to know the type of the key I'm trying to retrieve before retrieving it, is that even possible?
private fun Bundle.toMap(): Map<String?, *> {
val map = mutableMapOf<String?, Any?>()
for (key in keySet()) {
map[key] = get(key)
}
return map
}
Let's say I have an object
data class Person(
val name: String,
val surname: String,
val street: String,
val postalCode: String,
val telephoneNumber: String,
)
And then I have a list of persons :
val personsList = listOf(
Person(name="John", surname="Hams", street="Gariolg", postalCode="929429", telephoneNumer="+2142422422",),
Person(name="Karl", surname="Hamsteel", street="Gariolg", postalCode="124215", telephoneNumer="+3526522",),
Person(name="Stepf", surname="Hiol", street="Bubmp", postalCode="5342", telephoneNumer="+7574535",),
Person(name="Germa", surname="Foo", street="Hutioa", postalCode="235236", telephoneNumer="+112355",)
)
So now if the user types for instance Hams it should return John and Karl, because both have the word "Hams" inside the object. What I mean is doesn't matter if the user types postalCode, name, or whatever I'd like to loop throughout the object to check if there's any coincidence.
How i would do it, is create a function inside the data class, say, for example, like this. This will check if any field inside your data class matches with the given string.
In my example i check if whole string matches, but you can change this however you want. You probably want it.contains(searchString) inside the any block.
fun checkIfStringMatches(searchString: String) : Boolean =
setOf(this.name, this.surname, this.strees, this.postalCode, this.telephone).any { it == string }
Then, you can use this function on your list of persons to filter if any object matches your string search.
personList.filter{it.checkIfStringMatches(mySearchString)} // this will return a list with all the objects that match your search criteria
The problem is that if you add more fields, you will have to change this function and add it to the listOf() block. But i don't know any way to do this automatically without reflection, which is not really recommended to use. If you still want to use it, here is a question on this topic. Kotlin: Iterate over components of object
Try this, it will work.
personsList.filter { it.surname.startsWith("Hams") }.map {
Log.d("filter_name", it.name)
}
Hey You can apply filter method on list and grab the expected output like below :
val filtered = personsList.filter { it.toString().contains("Hams", true) }
I would like to convert $document.data details to useful format so that I could use it for further applications. This is data from firestore documents.
private val mFireStore = FirebaseFirestore.getInstance()
mFireStore.collection("Users").whereEqualTo("lastName","H").whereEqualTo("firstName", "Uc").get()
.addOnSuccessListener{ documents ->
for(document in documents){
Log.d("TAG","${document.id}=>${document.data}")
Toast.makeText(applicationContext, "${document.id} => ${document.data}",
Toast.LENGTH_LONG).show()
}
}
.addOnFailureListener{exception ->
Log.w("TAG","Error getting documents:",exception)
Toast.makeText(applicationContext, "Failed",
Toast.LENGTH_LONG).show()
}
This is my code. Now when I run the code get this in the logcat
OL0rD4UfgHSh2K8UoTMnX6Xea6P2=>{lastName=H, image=, firstName=Uc, B=L, gender=, organization=, profileCompleted=0, mobile=0, blood group=o+, id=OL0rD4UfgHSh2K8UoTMnX6Xea6P2, email=jojoy09#gmail.com}
Now I want to convert this result to a useful format so that I could use it later. I wpuld like to convert the data so that I could load it in listview.
In the following for-loop:
for(document in documents) { ... }
The "document" object is of type DocumentSnapshot. When you call getData() on such an object, the type of object that is returned is a Map<String, Object>.
In Kotlin, this object is represented by Map<String, Any>. In order to get the data, you can simply iterate over the Map and get the data accordingly, using the following lines of code:
val map = document.data
for ((key, value) in map) {
Log.d("TAG", "$key = $value")
}
Or even simpler, using:
map.forEach { (key, value) -> Log.d("TAG", "$key = $value") }
However, if you only need, the value of a particular property, for example, the value of the email address, you can simply get it by using DocumentSnapshot#getString(String field) method:
val email = document.getString("email")
Log.d("TAG", email)
The result in the logcat will be:
jojoy09#gmail.com
.................
As I see in your screenshot, almost all of the properties are of type String. However, you can find different flavors for each type of field, like getLong(String field), getDouble(String field), getDate(String field), getTimestamp(String field), and so on.
Furthermore, if you need to get the entire document, and you want to convert it into an object of a specific class, as also #mehulbisht mentioned in his answer, you should use DocumentSnapshot#toObject(Class valueType). So assuming that you have a data class that looks like this:
data class User(
var email: String? = null,
var firstName: String? = null,
var lastName: String? = null,
//Other necessary fields
)
To convert the "document" object into an object of the "User" class, please use the following line of code:
val user = document.toObject(User::class.java)
Log.d("TAG", user.email)
The result in the logcat will be the same as above.
If you want to display a list of "User" objects in a ListView, then please check my answer from the following post:
What miss, with connect Firestore and ListView for random results in sample?
It's really simple to convert the Java code into Kotlin.
The Model that you used to set this data will be used here. You can convert the documents to your Model class using the .toObjects() method on it. Just use:
val myObjs = documents.toObjects(Model::class.java)
EDIT
For displaying this as a Log in Logcat use:
Log.d("myObjs ","""
$myObjs
""".trimIndent())
Do tell if this doesn't work for you :)
I have a problem that I really cannot solve.. Maybe You may help me. I need to sort an object list from API return that contains filters. The problem is those filters are dynamic, The object Order (the problematic filter) :
class Order(val field : String, val direction: String)
The field is an object attribute (column), the direction can be ASC or DESC.
The JSON can return more than one filter, so this can be :
order : {
field : "id",
direction : "ASC"
},
{
field : "creationDate"
direction : "DESC"
}
The problem is, I don't know how to create a dynamic function that can create a perfect sort in my list. I know I've got to do this :
return list.sortedWith(compareBy(List::id).thenByDescending(List::creationDate))
But Dynamically.. wow
KT
You can create a map from a property name to the comparator that compares orders by that property:
val comparators = mapOf<String, Comparator<Order>>(
"field" to compareBy { it.field },
"direction" to compareBy { it.direction }
)
Then you can pick comparators from that map by the given property names, change their sorting order with Comparator.reversed() extension function, and finally combine all these comparators into the single resulting comparator with Comparator.then(Comparator) function:
val givenOrder = listOf("field" to "ASC", "direction" to "DESC")
val resultingOrder = givenOrder
.map { (fieldName, direction) ->
comparators[fieldName]!!.let { if (direction == "DESC") it.reversed() else it }
}
.reduce { order, nextComparator -> order.then(nextComparator) }
val sortedList = list.sortedWith(resultingOrder)
I am guessing that the second ordering oly applies to those where the first is the same value
sortedWith + compareBy
compareBy takes a vararg of selectors which is just a array, so it can be constructed
val selectors: Array<(T) -> Comparable<*>?> = orders.map { TODO() }.toArray()
list.sortedWith(compareBy(*selectors))
i am thinking some extra function go go though all possible fields you could sort and uses either it.field or -(it.field) to create the selectors
also see this answer: Sort collection by multiple fields in Kotlin
This is the model I upload on Firebase:
public class OnlineMatch{
private User user1;
private User user2;
public OnlineMatch(User firstPlayer, User secondPlayer) {
this.user1 = firstPlayer;
this.user2 = secondPlayer;
}
}
Then I send data to Firebase in this way (kotlin):
fun createMatch(match: OnlineMatch) {
val matchList = database.child("multiplayer").push()
matchList.setValue(match)
}
Thus, my DB structure is the following:
If I expand a node I can see perfectly my objects: OnlineMatch(User1, User2)
Now I would like to query the db and obtain an ArrayList'<'OnlineMatch'>'.
I have already found the Firebase docs but I found nothing useful.
How can I do? Thanks in advance.
You did not find something useful because when you query against a Firebase database you get a Map and not ArrayList. Everything in Firebase is structured as pairs of key and value. Using an ArrayList is an anti-pattern when it comes to Firebase. One of the many reasons Firebase recommends against using arrays is that it makes the security rules impossible to write.
In Kotlin there is no need for getters and setters. Is true that behind the scenes those functions exists but there is no need to explicitly define them. To set those fields, you can use the following code:
val onlineMatch = OnlineMatch() //Creating an obect of OnlineMatch class
onlineMatch.user1 = userObject //Setting the userObject to the user1 field of OnlineMatch class
//onlineMatch.setUser(userObject)
As you probably see i have commented the last line because there is no need to use a setter in order to set a userObject.
And very important, don't forget to add the no argument constructor in your OnlineMatch class that is needed for Firebase.
public OnlineMatch() {}
Edit:
To actually get the data, just put a listener on the desired node and get the data out from the dataSnapshot object into a HashMap.
val map = HashMap<String, OnlineMatch>()
Then simply iterate over the HashMap like this:
for ((userId, userObject) in map) {
//do what you want with them
}
Or simply use the code below:
val rootRef = firebase.child("multiplayer")
rootRef.addListenerForSingleValueEvent(object : ValueEventListener {
override fun onCancelled(error: FirebaseError?) {
println(error!!.message)
}
override fun onDataChange(snapshot: DataSnapshot?) {
val children = snapshot!!.children
children.forEach {
println(it.toString())
}
}
})
Hope it helps.