I have an array of nulls that I initialize with Strings. Then I have to pass it to a function that requires Array<String> instead of Array<String?>. So how can I go around this issue?
val list_names = arrayOfNulls<String>(plant_list.size)
for(item in plant_list){ list_names.plus(item.name) }
val myListAdapter = MyListAdapter(activity!!,list_names,list_types,list_images) // list_names must be Array<String>
I also want to mention that changing it in the Adapter would only complicate things, so I would like to do it all from here.
If you are sure that no null-values will be in your nullable array, you can simply (unsafe) cast it and it will work, e.g.:
val myListAdapter = MyListAdapter(activity!!,list_names as Array<String>,list_types,list_images)
If you have null values in there it depends a bit. One approach is then to first filter out the null-values and pass the resulting array, e.g.:
list_names.filterNotNull().toTypedArray()
// or in case you have different types in there and want only want a single matching one:
list_names.filterIsInstance<String>().toTypedArray()
But if you can: try to omit holding that array of nullable type in the first place. Can't you just filter out null values and collect the non-nullable only? That would probably the easiest and nicest way to collect the names as Array<String>, e.g.:
val list_names = plant_list.mapNotNull { it.name }.toTypedArray()
To answer your direct question you can get a new Array without nulls using this:
val nonNullListNames = list_names.filterNotNull().toTypedArray()
But there are other issues with your code. There's no reason to create the array of nulls and add items to it. Every time you call list_names.plus(item.name) in your loop, you are creating a new Array that still has the original set of null values plus your new item(s).
Instead you can directly create a list of non-null items from the collection you're getting items from, and convert it to an Array:
val nonNullNamesArray = plant_list.map { it.name }.toTypedArray()
If your plant names are nullable, use this:
val nonNullNamesArray = plant_list.mapNotNull { it.name }.toTypedArray()
You cannot have a arrayOfNulls and convert a Nullable to a NonNull object.
What I recommend to you is:
val list_names = mutableListOf<String>()
plant_list.foreach {
list_names.add(it.name)
}
val myListAdapter = MyListAdapter(activity, list_names, list_types, list_images)
Related
Solving algorithm tasks and came to one interesting situation that before I did not pay attention to.
Here is example:
val testList1 = mutableListOf<String>()
testList1.add("f")
testList1.add("n")
Toast.makeText(this, testList1.size.toString(), Toast.LENGTH_SHORT).show()
In this code, my toast will return size 2. Which is ok and expected.
but let's take this example:
val testList2 = mutableListOf(mutableListOf<String>())
testList2.add(mutableListOf("sf", "fgs"))
testList2.add(mutableListOf("sw", "fgg"))
Toast.makeText(this, testList2.size.toString(), Toast.LENGTH_SHORT).show()
Here the toast shows size = 3 even though I added 2 elements (2 lists). So when instantiating it adds 1 emptyList as the first element.
Not a big problem to solve this, we can just:
var finalList = testList2.removeIf { it.isEmpty() }
But I am curious why this happens. Also is there any nice way to avoid it. Would like to know little bit more if possible
It is not strange that testList2 contains 3 objects. testList2 is constructed with an initial empty list.
val testList2 = mutableListOf(mutableListOf<String>())
// using
public fun <T> mutableListOf(vararg elements: T): MutableList<T> =
if (elements.size == 0) ArrayList() else ArrayList(ArrayAsCollection(elements, isVarargs = true))
Here, you can define an empty mutable list by these codes.
val testList: MutableList<MutableList<String>> = mutableListOf()
// or
val testList = mutableListOf<MutableList<String>>()
// using
public inline fun <T> mutableListOf(): MutableList<T> = ArrayList()
Whatever you pass to the mutableListOf function is the initial contents of the list it returns. Since you have nested a call of mutableListOf() inside the outer call to mutableListOf(), you are creating your list with an initial value of another MutableList.
If you want your list to start empty, don’t put anything inside the () when you call mutableListOf().
If you construct your list this way, you need to specify the type of the list, since it won’t have an argument to infer the type from.
Either
val testList2 = mutableListOf<MutableList<String>>()
or
val testList2: MutableList<MutableList<String>> = mutableListOf()
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) }
So what I'm trying to do is to write search logic. The problem is following filter does not work even tho I do have an element containing following letter. So what my question is why is it not returning the expected value and if I'm doing something wrong what is it.
the filter I'm trying to use:
model.data.filter { person -> person.employeeName.toLowerCase().contains("t")}.toMutableList()
where model is InfoModel type and InfoModel looks like this:
class InfoModel {
var status = ""
lateinit var data : MutableList<Data>
class Data {
var id = ""
#SerializedName("employee_name")
var employeeName = ""
#SerializedName("employee_salary")
var employeeSalary = ""
#SerializedName("employee_age")
var employeeAge = ""
#SerializedName("profile_image ")
var profileImage = "https://www.pngitem.com/pimgs/m/146-1468479_my-profile-icon-blank-profile-picture-circle-hd.png"
}
}
I'm guessing due to lack of context, but maybe you're doing something like this:
model.data.filter { person -> person.employeeName.toLowerCase().contains("t")}.toMutableList()
println(model.data) // Still prints original unfiltered list!
The first line of code creates a new MutableList and promptly throws it away, because you don't assign it to anything. So the original list pointed at by model.data is left unchanged.
Since data is a MutableList, you can modify it in place using retainAll:
model.data.retainAll { person -> person.employeeName.toLowerCase().contains("t") }
Alternatively, you could reassign the result of your original code back to model.data:
model.data = model.data.filter { person -> person.employeeName.toLowerCase().contains("t")}.toMutableList()
To me it looks like kind of code smell to have a MutableList assigned to a read-write var, because then it's mutable in two different ways. Why does it even have to be lateinit if it's mutable? You could instantiate with an empty list and fill it later.
In general var data: List should be preferred to val data: MutableList unless you are needing to optimize performance for huge lists. And var data: MutableList is just inviting troubles.
I get an array from an API:
val pics = response.getJSONArray("pics")
pics contains like:
["https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/19\/55\/497173801955.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/10\/34\/242830811034.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/86\/23\/808728238623.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/90\/41\/146747399041.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/47\/41\/672475854741.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/63\/94\/771076926394.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/36\/42\/182330463642.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/29\/96\/948397532996.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/82\/54\/761385508254.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/41\/42\/142837364142.jpg","https:\/\/www.bla.com\/extern\/v\/pics\/mitte\/66\/25\/215324906625.jpg"]
I need to get that into an ArrayList<String>
This is one of multiple tries after converting JAVA solutions to kotlin:
val list = ArrayList<String>()
for (i in 0 until pics.length()) {
list.add(pics.getJSONObject(i).getString("name"))
}
And then when I try to use list in ViewPager then I get type mismatch:
Required: Array<String>
Found:kotlin.collections.ArrayList<String
How to do this??
Why can't it be all just simple array() like in PHP smh this is all beyond annoying
Array<String> and ArrayList<String> are 2 different types.
What you need to provide is Array<String> but what you are actually providing is ArrayList<String>.
val list = Array(pics.length()) {
pics.getString(it)
}
I have declared ArrayList like,
var otherSeriesList = ArrayList<String>()
And trying to get data from resource by following,
otherSeriesList = ArrayList<String>(Arrays.asList(resources.getStringArray(R.array.get_other_series)))
But I am getting error. Please see the image-
How should I create ArrayList from resource string-array?
Simple do like this-
otherSeriesList = ArrayList<String>(Arrays.asList(*resources.getStringArray(R.array.get_other_series)))
* will pass the Array as vararg
Just use ArrayList(resources.getStringArray( ... ).toMutableList()) instead.
If you don't need to use ArrayList exactly in your code, then you can change type of property to MutableList<String> and call resources.getStringArray( ... ).toMutableList()
Or you can use spread operator on your array and create ArrayList via call arrayListOf(*context.resources.getStringArray())
You can to declare it as MutableList(). Also cast that StringArray to String before that.
var otherSeriesList: MutableList<String> = Arrays.asList(resources.getStringArray(R.array.get_other_series).toString())
Or you can do it like,
var otherSeriesList: MutableList<String> = resources.getStringArray(R.array.get_other_series).toMutableList()
you can create an extension function
private fun Array<String>.getAsArrayList(): ArrayList<String> {
val list = ArrayList<String>()
this.forEach { it->list.add(it) }
return list
}
and call it like this
val list = resources.getStringArray(R.array.array).getAsArrayList()
If you have an array, simply call toList() on it.
val arr = arrayOf(1, 2)
val list = arr.toList()
Alternatively, there’s also a toMutableList() extension available.
Note that you can declare lists in Kotlin like this:
val list = listOf<String>(1, 2)
To be sure to get an ArrayList, use arrayListOf().