Kotlin Dynamic Array implementation with generics - android

I'm learning data structures and trying to implement a dynamic array from scratch in Kotlin using generics. I came up with the following implementation using a MutableList but that feels like cheating 😅. Am I doing this correctly or is there another/better way that allows me to learn by implementing the individual operations manually? What's the usual way others go about this?
class DynamicArray<T>(
private var values: MutableList<T>
) {
var length: Int = values.size
private set
var isEmpty: Boolean = length > 0
private set
fun getValues() = values
// O(1) time complexity
fun lookup(index: Int) = values[index]
// O(1) time complexity
fun push(item: T): MutableList<T> {
values.add(length, item)
length++
return values
}
// O(n) time complexity because we have to shift remaining items
fun remove(item: T): MutableList<T> {
values.remove(item)
length--
return values
}
}

Specifically you're saying that in order for your DynamicArray to exist, you need an already implemented mutable list (dynamic array) structure to rely upon.
So if you're trying to learn how these data structures are made, you should try to make one instead of using one. At the moment you're just delegating the difficult parts to someone else's work.
Try implementing this using only the Array type to make an ArrayList style implementation, or try not using an Array at all to implement a LinkedList type structure.

Here's a quick implementation that uses Array as the underlying DS.
It implements a MutableIterable which is basically an Iterable that also allows you to remove an element while iterating.
#Suppress("UNCHECKED_CAST")
class DynamicArray<T>(
private var size: Int,
private val expansionFactor: Float = 2f,
private val init: (Int) -> T) : MutableIterable<T> {
var capacity: Int = size
private set
private var arr: Array<Any?> = Array(size, init)
inner class DynamicArrayIterator: MutableIterator<T>{
val iterator = arr.iterator()
var index = -1
override fun hasNext(): Boolean {
return index<size-1
}
override fun next(): T {
if(iterator.hasNext()) index++
else throw NoSuchElementException()
return iterator.next() as T
}
override fun remove() {
removeAt(index--)
}
}
override fun iterator(): MutableIterator<T> = DynamicArrayIterator()
fun size(): Int = size
//O(1)
fun get(index: Int): T {
if(index > size-1) throw IndexOutOfBoundsException()
return arr[index] as T
}
//O(1)
fun set(index: Int, element: T) {
if(index > size-1) throw IndexOutOfBoundsException()
arr[index] = element
}
//O(1) amortized
fun add(element: T){
if(size == capacity){
capacity = (expansionFactor*size).toInt()
val newArr = Array<Any?>(capacity, init = init)
arr.forEachIndexed { index, any -> newArr[index] = any as T }
arr = newArr
}
arr[size] = element
size++
}
//O(n)
fun removeAt(index: Int): T{
if(index > size-1) throw IndexOutOfBoundsException()
val element = arr[index] as T
for( i in index until size){
arr[i] = arr[i+1]
}
size--
return element
}
//O(n)
fun remove(element: T): Boolean{
for(i in 0 until size){
if(arr[i] == element) {
removeAt(i)
return true
}
}
return false
}
//O(n)
override fun toString(): String {
val stringBuilder = StringBuilder()
stringBuilder.append("[")
var index = 0
do{
if (index in 1 until size)
stringBuilder.append(", ")
stringBuilder.append(arr[index])
index++
} while (index < size)
return stringBuilder.append("]").toString()
}
}

Related

How to display a unique string message based off of index position and value of an ArrayList Kotlin?

I have a bunch of integers in an ArrayList. The values are either 1 or 0 at any given time. I have a unique string error message that I would like to display for each of these items if any of the values switch to 1. I have a single textView where I would like to display the current error message if there is one.
For some reason, I cannot understand how to do this. Is there a data structure that I can leverage to solve this problem efficiently?
You can write an anonymous subclass of ArrayList or LinkedList that overrides the set function to do some action whenever a value is changed:
val myList = object: ArrayList<Int>() {
override fun set(index: Int, element: Int): Int {
return super.set(index, element).also { previousElement ->
if (previousElement == 0 && element == 1) {
showErrorMessageForIndex(index)
}
}
}
}
// where showErrorMessageForIndex is a function that sets a message on your text view.
If you do this kind of thing in multiple places in your app, you can generalize it into a reusable class like this:
class MyArrayList<T>(
val onValueChange: (index: Int, oldValue: T, newValue: T)-> Unit
): ArrayList<T>() {
override fun set(index: Int, element: T): T {
return super.set(index, element).also { previousElement ->
if (previousElement != element) {
onValueChange(index, previousElement, element)
}
}
}
}
Then when you create the list, use:
val myList = MyArrayList<Int> { index, oldValue, newValue ->
if (oldValue == 0 && newValue == 1) {
showErrorMessageForIndex(index)
}
}

Get the returned list from firestore based on condition when a value is passed to firestore function

I am trying to return a list from inside firestore function based on if a condition is true.I want to return different lists when different categories are selected.
I tried:
putting the return statement out of firestore function which did not work and returned empty list due to firestore async behaviour.
creating my own callback to wait for Firestore to return the data using interface as I saw in some other questions but in that case how am i supposed to access it as my function has a Int value(i.e.private fun getRandomPeople(num: Int): List<String>)?
What could be the way of returning different lists for different categories based on firestore conditions?
My code(Non Activity class):
class Board// Create new game
(private val context: Context, private val board: GridLayout) {
fun newBoard(size: Int) {
val squares = size * size
val people = getRandomPeople(squares)
createBoard(context, board, size, people)
}
fun createBoard(context: Context, board: GridLayout, size: Int, people: List<String>) {
destroyBoard()
board.columnCount = size
board.rowCount = size
var iterator = 0
for(col in 1..size) {
for (row in 1..size) {
cell = RelativeLayout(context)
val cellSpec = { GridLayout.spec(GridLayout.UNDEFINED, GridLayout.FILL, 1f) }
val params = GridLayout.LayoutParams(cellSpec(), cellSpec())
params.width = 0
cell.layoutParams = params
cell.setBackgroundResource(R.drawable.bordered_rectangle)
cell.gravity = Gravity.CENTER
cell.setPadding(5, 0, 5, 0)
text = TextView(context)
text.text = people[iterator++]
words.add(text.text as String)
text.maxLines = 5
text.setSingleLine(false)
text.gravity = Gravity.CENTER
text.setTextColor(0xFF000000.toInt())
cell.addView(text)
board.addView(cell)
cells.add(GameCell(cell, text, false, row, col) { })
}
}
}
private fun getRandomPeople(num: Int): List<String> {
val mFirestore: FirebaseFirestore=FirebaseFirestore.getInstance()
val mAuth: FirebaseAuth=FirebaseAuth.getInstance()
val currentUser: FirebaseUser=mAuth.currentUser!!
var validIndexes :MutableList<Int>
var chosenIndexes = mutableListOf<Int>()
var randomPeople = mutableListOf<String>()
mFirestore.collection("Names").document(gName).get().addOnSuccessListener(OnSuccessListener<DocumentSnapshot>(){ queryDocumentSnapshot->
var categorySelected:String=""
if (queryDocumentSnapshot.exists()) {
categorySelected= queryDocumentSnapshot.getString("selectedCategory")!!
print("categoryselected is:$categorySelected")
Toast.makeText(context, "Got sel category from gameroom:$categorySelected", Toast.LENGTH_LONG).show()
when(categorySelected){
"CardWords"->{
for (i in 1..num) {
validIndexes=(0..CardWords.squares.lastIndex).toMutableList()
val validIndexIndex = (0..validIndexes.lastIndex).random()
val peopleIndex = validIndexes[validIndexIndex]
chosenIndexes.add(peopleIndex)
val person = CardWords.squares[peopleIndex]
randomPeople.add(person)
validIndexes.remove(peopleIndex)
peopleIndexes = chosenIndexes.toList()
}
}
else->{}
}
}
else {
Toast.makeText(context, "Sel category does not exist", Toast.LENGTH_LONG).show()
}
}).addOnFailureListener(OnFailureListener { e->
val error=e.message
Toast.makeText(context,"Error:"+error, Toast.LENGTH_LONG).show()
})
return randomPeople.toList()
}
}
Activity A:
Board(this, gridLay!!)

Sorting Strings that contains number in kotlin

I wanna sort some strings that contain numbers but after a sort, it becomes like this ["s1", "s10", "s11", ... ,"s2", "s21", "s22"]. after i search i fount this question with same problem. but in my example, I have mutableList<myModel>, and I must put all string in myModel.title for example into a mutable list and place into under code:
val sortData = reversedData.sortedBy {
//pattern.matcher(it.title).matches()
Collections.sort(it.title, object : Comparator<String> {
override fun compare(o1: String, o2: String): Int {
return extractInt(o1) - extractInt(o2)
}
fun extractInt(s: String): Int {
val num = s.replace("\\D".toRegex(), "")
// return 0 if no digits found
return if (num.isEmpty()) 0 else Integer.parseInt(num)
}
})
}
I have an error in .sortedBy and Collections.sort(it.title), may please help me to fix this.
you can use sortWith instead of sortBy
for example:
class Test(val title:String) {
override fun toString(): String {
return "$title"
}
}
val list = listOf<Test>(Test("s1"), Test("s101"),
Test("s131"), Test("s321"), Test("s23"), Test("s21"), Test("s22"))
val sortData = list.sortedWith( object : Comparator<Test> {
override fun compare(o1: Test, o2: Test): Int {
return extractInt(o1) - extractInt(o2)
}
fun extractInt(s: Test): Int {
val num = s.title.replace("\\D".toRegex(), "")
// return 0 if no digits found
return if (num.isEmpty()) 0 else Integer.parseInt(num)
}
})
will give output:
[s1, s21, s22, s23, s101, s131, s321]
A possible solution based on the data you posted:
sortedBy { "s(\\d+)".toRegex().matchEntire(it)?.groups?.get(1)?.value?.toInt() }
Of course I would move the regex out of the lambda, but it is a more concise answer this way.
A possible solution can be this:
reversedData.toObservable()
.sorted { o1, o2 ->
val pattern = Pattern.compile("\\d+")
val matcher = pattern.matcher(o1.title)
val matcher2 = pattern.matcher(o2.title)
if (matcher.find()) {
matcher2.find()
val o1Num = matcher.group(0).toInt()
val o2Num = matcher2.group(0).toInt()
return#sorted o1Num - o2Num
} else {
return#sorted o1.title?.compareTo(o2.title ?: "") ?: 0
}
}
.toList()
.subscribeBy(
onError = {
it
},
onSuccess = {
reversedData = it
}
)
As you state that you need a MutableList, but don't have one yet, you should use sortedBy or sortedWith (in case you want to work with a comparator) instead and you get just a (new) list out of your current one, e.g.:
val yourMutableSortedList = reversedData.sortedBy {
pattern.find(it)?.value?.toInt() ?: 0
}.toMutableList() // now calling toMutableList only because you said you require one... so why don't just sorting it into a new list and returning a mutable list afterwards?
You may want to take advantage of compareBy (or Javas Comparator.comparing) for sortedWith.
If you just want to sort an existing mutable list use sortWith (or Collections.sort):
reversedData.sortWith(compareBy {
pattern.find(it)?.value?.toInt() ?: 0
})
// or using Java imports:
Collections.sort(reversedData, Compatarator.comparingInt {
pattern.find(it)?.value?.toInt() ?: 0 // what would be the default for non-matching ones?
})
Of course you can also play around with other comparator helpers (e.g. mixing nulls last, or similar), e.g.:
reversedData.sortWith(nullsLast(compareBy {
pattern.find(it)?.value
}))
For the samples above I used the following Regex:
val pattern = """\d+""".toRegex()
I wrote a custom comparator for my JSON sorting. It can be adapted from bare String/Number/Null
fun getComparator(sortBy: String, desc: Boolean = false): Comparator<SearchResource.SearchResult> {
return Comparator { o1, o2 ->
val v1 = getCompValue(o1, sortBy)
val v2 = getCompValue(o2, sortBy)
(if (v1 is Float && v2 is Float) {
v1 - v2
} else if (v1 is String && v2 is String) {
v1.compareTo(v2).toFloat()
} else {
getCompDefault(v1) - getCompDefault(v2)
}).sign.toInt() * (if (desc) -1 else 1)
}
}
private fun getCompValue(o: SearchResource.SearchResult, sortBy: String): Any? {
val sorter = gson.fromJson<JsonObject>(gson.toJson(o))[sortBy]
try {
return sorter.asFloat
} catch (e: ClassCastException) {
try {
return sorter.asString
} catch (e: ClassCastException) {
return null
}
}
}
private fun getCompDefault(v: Any?): Float {
return if (v is Float) v else if (v is String) Float.POSITIVE_INFINITY else Float.NEGATIVE_INFINITY
}

How to pick every time new or unique random item from a array list in android?

I need to pick a new item from a list that hasn't been picked already until there are no more.
Here is my code:
private var quizQuestionList: ArrayList<Quiz>
private var pickedItems: ArrayList<Int>
private var random: Random = Random()
private fun pickItem(): Quiz {
var index = random?.nextInt(quizQuestionList!!.size)
if (pickedItems.contains(index)) {
index = random?.nextInt(quizQuestionList!!.size)
pickedItems.add(index)
} else {
pickedItems.add(index)
}
val item = quizQuestionList!!.get(index!!)
return item
}
Please suggest any solution that gives me a new item every time. I used an int list for all previously picked items and check every time when picked new item but I didn't get success.
It isn't obvious what you are looking for, but it looks like you want to show different Quiz question from ArrayList. In condition of, when that question is shown, no more same question will be shown. Here is how you should do, I will give you just the logic you could try it yourself:
import java.util.Random
fun main(args: Array<String>) {
val random = Random()
var randomInt: Int
var pickedInt: MutableSet<Int> = mutableSetOf()
fun rand(from: Int, to: Int): Int{
do{
randomInt = random.nextInt(to - from) + from
}while(pickedInt.contains(randomInt))
pickedInt.add(randomInt)
return randomInt
}
while(pickedInt.size < 9){
var differentNumber = rand(1,11)
println(differentNumber)
}
}
This will print nine different Number. The way I choosing MutableSet is because it will only have unique values, no duplicated value. Hope it helps!
here is code for same::
val arrayList = ArrayList<String>()
arrayList.add("a")
arrayList.add("b")
arrayList.add("c")
arrayList.add("d")
arrayList.add("e")
arrayList.add("f")
arrayList.add("g")
arrayList.add("h")
arrayList.add("i")
arrayList.add("j")
arrayList.add("k")
random = Random()
Low = 0
High = arrayList.size
val generateRandom = findViewById<View>(R.id.generateRandom) as Button
generateRandom.setOnClickListener {
val Result = random.nextInt(High - Low) + Low
Log.v("check", arrayList[Result])
}
Please let me know if need more!!
Try this way
class MainActivity : AppCompatActivity() {
private var arrayList = ArrayList<String>()
private var lastItem = -1
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
for (i in 0..9) {
arrayList.add(i.toString())
}
btnData.setOnClickListener {
Log.e("RANDOM_NUMBER", "" + getRandomItemFromList())
}
}
private fun getRandomItemFromList(): Int {
val randomValue = Random().nextInt(arrayList.size)
return if (randomValue != lastItem) {
lastItem = randomValue
randomValue
} else {
getRandomItemFromList()
}
}
}
I made this extension for the ArrayList class in Kotlin you can use it multiple times in only one line.
fun <T> ArrayList<T>.generateRandomItems(numberOfItems: Int): ArrayList<T> {
val range = if(numberOfItems > this.size){this.size}else{numberOfItems}
val randomItems = ArrayList<T>()
for (i in 0..range) {
var randomItem: T
do {
randomItem = this.random()
} while (randomItems.contains(randomItem))
randomItems.add(randomItem)
}
return randomItems
}
Usage:
val randomUsersList = usersList.generateRandomItems(20)
Note: the usersList is the list that has items to generate random items from.

Remove data from list while iterating kotlin

I am new to kotlin programming. What I want is that I want to remove a particular data from a list while iterating through it, but when I am doing that my app is crashing.
for ((pos, i) in listTotal!!.withIndex()) {
if (pos != 0 && pos != listTotal!!.size - 1) {
if (paymentsAndTagsModel.tagName == i.header) {
//listTotal!!.removeAt(pos)
listTotal!!.remove(i)
}
}
}
OR
for ((pos,i) in listTotal!!.listIterator().withIndex()){
if (i.header == paymentsAndTagsModel.tagName){
listTotal!!.listIterator(pos).remove()
}
}
The exception which I am getting
java.lang.IllegalStateException
use removeAll
pushList?.removeAll { TimeUnit.MILLISECONDS.toMinutes(
System.currentTimeMillis() - it.date) > THRESHOLD }
val numbers = mutableListOf(1,2,3,4,5,6)
val numberIterator = numbers.iterator()
while (numberIterator.hasNext()) {
val integer = numberIterator.next()
if (integer < 3) {
numberIterator.remove()
}
}
It's forbidden to modify a collection through its interface while iterating over it. The only way to mutate the collection contents is to use Iterator.remove.
However using Iterators can be unwieldy and in vast majority of cases it's better to treat the collections as immutable which Kotlin encourages. You can use a filter to create a new collections like so:
listTotal = listTotal.filterIndexed { ix, element ->
ix != 0 && ix != listTotal.lastIndex && element.header == paymentsAndTagsModel.tagName
}
The answer by miensol seems perfect.
However, I don't understand the context for using the withIndex function or filteredIndex. You can use the filter function just by itself.
You don't need access to the index the list is at, if you're using
lists.
Also, I'd strongly recommend working with a data class if you already aren't. Your code would look something like this
Data Class
data class Event(
var eventCode : String,
var header : String
)
Filtering Logic
fun main(args:Array<String>){
val eventList : MutableList<Event> = mutableListOf(
Event(eventCode = "123",header = "One"),
Event(eventCode = "456",header = "Two"),
Event(eventCode = "789",header = "Three")
)
val filteredList = eventList.filter { !it.header.equals("Two") }
}
The following code works for me:
val iterator = listTotal.iterator()
for(i in iterator){
if(i.haer== paymentsAndTagsModel.tagName){
iterator.remove()
}
}
You can also read this article.
People didn't break iteration in previous posts dont know why. It can be simple but also with extensions and also for Map:
fun <T> MutableCollection<T>.removeFirst(filter: (T) -> Boolean) =
iterator().removeIf(filter)
fun <K, V> MutableMap<K, V>.removeFirst(filter: (K, V) -> Boolean) =
iterator().removeIf { filter(it.key, it.value) }
fun <T> MutableIterator<T>.removeFirst(filter: (T) -> Boolean): Boolean {
for (item in this) if (filter.invoke(item)) {
remove()
return true
}
return false
}
Use a while loop, here is the kotlin extension function:
fun <E> MutableList<E>.removeIfMatch(isMatchConsumer: (existingItem: E) -> Boolean) {
var index = 0
var lastIndex = this.size -1
while(index <= lastIndex && lastIndex >= 0){
when {
isMatchConsumer.invoke(this[index]) -> {
this.removeAt(index)
lastIndex-- // max is decreased by 1
}
else -> index++ // only increment if we do not remove
}
}
}
Typically you can use:
yourMutableCollection.removeIf { someLogic == true }
However, I'm working with an Android app that must support APIs older than 24.
In this case removeIf can't be used.
Here's a solution that is nearly identical to that implemented in Kotlin Collections that doesn't rely on Predicate.test - which is why API 24+ is required in the first place
//This function is in Kotlin Collections but only for Android API 24+
fun <E> MutableCollection<E>.removeIff(filter: (E) -> Boolean): Boolean {
var removed = false
val iterator: MutableIterator<E> = this.iterator()
while (iterator.hasNext()) {
val value = iterator.next()
if (filter.invoke(value)) {
iterator.remove()
removed = true
}
}
return removed
}
Another solution that will suit small collections. For example set of listeners in some controller.
inline fun <T> MutableCollection<T>.forEachSafe(action: (T) -> Unit) {
val listCopy = ArrayList<T>(this)
for (element: T in listCopy) {
if (this.contains(element)) {
action(element)
}
}
}
It makes sure that elements of collection can be removed safely even from outside code.

Categories

Resources