What is the difference between map and mapTo in Kotlin - android

Trying to understand the difference between map and mapTo in kotlin. Could anyone help me out in explaining the difference using some examples

map creates a new list internally, and puts its results into that list, then it returns that list:
val mapResult = listOf(1, 2, 3).map { it * 2 } // you get a new list instance returned
If you use mapTo instead, you can specify the destination where it places the mapped elements, by providing your own list as the first parameter:
val myList = ArrayList<Int>()
val mapToResult = listOf(1, 2, 3).mapTo(myList) { it * 2 }
If the list you're provided already has elements in it, those will be kept, and the new ones will be added to those. It also returns the destination list for convenience.

map: map can transform your data(List) and can return either complete modified list or List of a variable of model, for ex:
You have a model:
data class Student(var id:String, var name:String, var className:String)
Now from arrayOfStudent, we want all the name of students in capital letters, so apply map like this:
val listOfNamesInCapitalLetters= arrStudent.map {
it.name= it.name.toUpperCase()
}
Log.d("map_test", "student's name: $listOfNamesInCapitalLetters")
The output will be:
[AMIT, VIJAY, SUMIT, KARAN, SMAEER]
Now, what if you want the whole student list, with name in capital letters and className is increased by 1, let's do this:
val result= arrStudent.map {
it.name= it.name.toUpperCase() // transforming name to upper case
it.className=it.className+1 // increasing class by 1
it // <- Note that we return it, because list will be prepared of the object which is returned by last statement of map
}
Log.d("modified_list", result.toString())
The output will be:
[Student(id=1, name=AMIT, className=6), Student(id=2, name=VIJAY, className=7), Student(id=3, name=KARAN, className=8), Student(id=4, name=VIRAT, className=9), Student(id=5, name=SAM, className=10)]
mapTo: If you want to transform your list into a different type of list then use mapTo, for example, we have a different data class named: CompactStudent
data class CompactStudent(val id:String, val name:String)
Now if we want to convert List to List, note that CompactStudent contains id and name but not the className as compared to Student model, so to do this:
val arrayList=ArrayList<CompactStudent>()
arrStudent.mapTo(arrayList){
CompactStudent(it.id,it.name)
}
Log.d("studentCompact", arrayList.toString())
Output will be:
[StudentCompct(id=1, name=AMIT), StudentCompct(id=2, name=VIJAY), StudentCompct(id=3, name=KARAN), StudentCompct(id=4, name=VIRAT), StudentCompct(id=5, name=SAM)]

Related

How to convert string which have array and string elements inside it, to fetch each element from the array in Kotlin [Android]

My output looks like this :
["Floor 0","Floor 1","Floor 2"]
It comes as a string. But I want to fetch each element of this array. How can I do this using Kotlin ?
implement this library Gson
you can use it like this
val text = "[\"Floor 0\",\"Floor 1\",\"Floor 2\"]"
val array = Gson().fromJson(text, ArrayList::class.java)
array.forEach {
Log.e(TAG, "onCreate: it $it")
}
Just use regular expressions to create a match for each CharSequence between the double quotes. As you want to use only the values between the quotes, you can extract the first index group values. The following code snippet does what you are asking for in Kotlin:
val str = "[\"Floor 0\",\"Floor 1\",\"Floor 2\"]"
val pattern = Regex( "\"(.*?)\"")
val fetched_elements = pattern.findAll(str).map {
it.groupValues[1]
}.toList()
// creates the list: [Floor 0, Floor 1, Floor 2]
Use also this RegExr example to explore this in detail with explanation.
If your internal strings aren't allowed to have commas, you could do it with a split function to convert it into a list:
var lst = str.replace("\"", "").split(",")
If your internal strings can have trailing whitespace, this would be better:
var lst = str.replace("\"", "").split(",").map { it.trim() }
In the above code lines, the replace function removes the quotes surrounding each internal string; the split separates the string at each comma; and the trim function removes any surrounding whitespace characters.
If your internal strings can contain commas, you're better off learning about and using regular expressions as mentioned in another answer.

How to save a list of objects with Proto DataStore

If I have the following class, how can I save a list of it with Proto DataStore?
data class Tag(
val id: int,
val name: String
)
All guides that I saw were teaching how to save only a single object. Is it possible to have a list of it?
You should consider storing list of content in Room, Even proto-datastore isnt a proper solution to store complex stuff,
If you still want then, I will suggest you to restrict the data stored to 10-15 items
to the code --->
Create your proto file, repeated is used to create list type for Java
message Student {
string id = 1;
string name = 2;
}
message ClassRoom {
string teacher = 1;
repeated Student students = 2; // repeated => list
}
Inside your proto-store,
dataStore.updateData { store ->
store.toBuilder()
.clearStudents() // clear previous list
.setAllStudents(students)// add the new list
.build()
}
if you want example checkout my sample app, read the data/domain layer
https://github.com/ch8n/Jetpack-compose-thatsMine

Android kotlin assigning a list row to variable error

I am trying to update the view state in the view model using a row from a list object
val update = getCurrentViewStateOrNew()
val updatedRow = update.editLog?.distortion?.get(0)?.copy(
allOrNothing = allOrNothing ?: null,
)
update.editLog?.distortion?.get(0) = updatedRow
setViewState(update)
On the second last line the IDE has underlined the .get(0) in red stating "variable expected". I do not know what it wants from me or how to get this error to go away. I'm simply trying to update the current view state.
You are trying to set a value using a getter method.
You need to get the list, update the first index, then set that updated list to the ViewState.
val update = getCurrentViewStateOrNew()
val updatedRow = update.editLog?.distortion?.get(0)?.copy(
allOrNothing = allOrNothing ?: null,
)
val distortions: ArrayList<Distortion> = ArrayList()
update.editLog?.distortion?.let{ list ->
distortions.addAll(list)
}
distortions.set(0, updatedRow)
update.editLog?.distortion = distortions
setViewState(update)
Kotlin has special operators for collections called get and set.
Using get you can only return a value.
Using set you can only set a value.
It means you cannot assign a new value to the result returned by the get operator.
What you need to do instead is either use set operator which accepts two arguments: index of the element and the element itself.
update.editLog?.distortion?.set(0, updatedRow)
Alternative is to use brackets on an unwrapped array, making sure it is not null:
update.editLog?.distortion?.let {
it[0] = updatedRow
}
Read more here about updating lists.
Read more here about retrieving values from a list.
You're trying to make an assignment to the return value of the get method.
You probably meant to set that element of the list:
update.editLog?.distortion?.set(0, updatedRow)
You can't use the normal [] syntax due to it being nullable.

Change item's data type in a List or array in Kotlin

how can i change item's data type in arrays or lists in kotlin ?
i found a usual way but i need an easier and faster and better way to change data type of an array :)
fun typeChanger (data:MutableList<Number>): DoubleArray {
val result = mutableListOf<Double>()
for (i in data.iterator()){
result.add(i.toDouble())
}
return result.toDoubleArray()
}
val x = mutableListOf<Number>(+1,+1,-1,-1)
val xx:DoubleArray = typeChanger(x) // It works but i need an easier and faster and better way :)
Array map is your friend. You could keep your function and simplify, or remove it completely as below:-
val xx = x.map { it.toDouble() }
Once it's a list of doubles, you can then leave as a list or use .toDoubleArray() if you need an array.

Sorting Secondary Collection using Primary Sorted Collection's field

I have an unsorted List of Users and a sorted list of Users id. Id is a string.
I want to sort first list by second. How to do that in Kotlin?
data class User(val name : String, val id : String)
val unsorted = listOf<User>(
User("Max", "b12s11"),
User("Joe", "dj1232"),
User("Sam", "23d112"),
User("Tom", "k213i1")
)
val sorted = listOf<String>(
"dj1232",
"b12s11",
"k213i1",
"23d112"
)
// what I need
val result = listOf<User>(
User("Joe", "dj1232"),
User("Max", "b12s11"),
User("Tom", "k213i1"),
User("Sam", "23d112")
)
Shorter solution:
val result = unsorted.sortedBy { sorted.indexOf(it.id) }
Although the other answers show a solution to your problem, it seems to me that a Map<String, User> might better fit the purpose, e.g.:
val usersByid = unsorted.associateBy { it.id }
val result = sorted.mapNotNull {
usersById[it]
}
I assume that every id is only once in the list, therefore I used associateBy. Otherwise it wouldn't be an id for me ;-)
The main difference between this solution and others is that this solution only returns the entries that are also in the sorted-list. Note that if you have users for which you have no id in the sorted-list, this solution omits them, whereas other solutions put those entries at the front of the list. Depends on what you really want.
It could be that this solution is more efficient than the others. Accessing the Map should be much faster then reiterating all the entries over and over again (which both indexOf and first basically do).
I don't know of any Kotlin syntax for doing this, sorting one list by another, but this solution should work for you (the way I understood this question, was that you want to sort according to the Id's in sorted):
val correctList = arrayListOf<User>()
sorted.forEach { sortedId ->
correctList.add(unsorted.first {
it.id == sortedId
})
}
It iterates over your sorted list of Id's and takes the item in the first list (unsorted) which matches that ID and adds it to correctList
Edit: see answer from #Andrei Tanana for a better kotlin answer than mine : sort unsorted collection with another sorted collection's field it's pretty cool :D
Edit2: Thanks to #Roland for pointing out, I can simplify my answer even further with :
val correctList = sorted.map { sortedId -> unsorted.first { it.id == sortedId } }

Categories

Resources