here i tried to reproduce my problem .. for set ...
# getting-started
a
here i tried to reproduce my problem .. for set of custom data filter and then remove is not working but remove if is working fine.. and if any inner value not change then its works ..
Copy code
import org.junit.Test

class TestMutableSetDelete {
    @Test
    fun testRemoveMutableSet(){
        val data = TestSetList(mutableSetOf(), mutableSetOf())
        add(data)
        change(data)
        //deletes not work in any inner value ever change 
        delete(data)
        // removeIf always works . but i my code need to work below api 24 too.
//        data.span.removeIf { it.start==it.end }
        // FIXME: without change this works . but if change happend its not
        data.range.forEach { println("start > ${it.start} > ${it.end}") }
        assert(data.range.size==2)
    }
}
data class TestSetList(
    val range: MutableSet<Range> = mutableSetOf(),
    val para: MutableSet<Para> = mutableSetOf()
)
data class Para(
    val start:Int,
    val end:Int
)
data class ChangedData(
    var name:String="",
    var age:Long
)
data class Range(
    val start:Int,
    val end:Int,
    val changedData: ChangedData
)
fun add(data:TestSetList){
    val cd =ChangedData("naser",26)
    data.range.add(Range(0,0,cd))
    data.range.add(Range(1,2,cd))
    data.range.add(Range(1,5,cd))
    data.range.add(Range(2,2,cd))
    data.range.add(Range(3,3,cd))
}
fun change(data: TestSetList){
    //simulate some change in the process .
    data.range.forEach { it.changedData.name = it.start.toString() }
}
fun delete(data:TestSetList){
    data.range.filter { it.start == it.end }.forEach { data.range.remove(it) }
}
1
i
I ran your test as-is, and it did not fail 😕
ah wait, assertions not on.
a
check this .. the value that are equal ( start == end ) is still there ..
this one with remove if
this time out of function ,, and tried both filter and if .. not works either .. why though ?
m
I don't know exactly whats happening underwater, maybe someone else can give some light on that but: You shouldn't ever alter the way a class maps its equality AFTER insertion into a set, since equality is checked at insertion-time. Consider this: You have a class with a single var, you insert 5 different values of this class; afterwards, you assign all these vars the same value. The result is a set of 5 elements whom are all equal. Which is counterproductive to what you initially wanted.
from the docs from java itself: Note: Great care must be exercised if mutable objects are used as set elements. The behavior of a set is not specified if the value of an object is changed in a manner that affects equals comparisons while the object is an element in the set. A special case of this prohibition is that it is not permissible for a set to contain itself as an element.
There are multiple possible variants to work with instead; I'd consider using a Map instead like so:
Copy code
class TestMutableSetDelete {
    fun testRemoveMutableSet() {
        val data = TestSetList(mutableMapOf(), mutableSetOf())
        add(data)
        change(data)
        delete(data)
        data.range.forEach { println("start > ${it.key.start} > ${it.key.end}") }
        assert(data.range.size == 2)
    }
}
data class TestSetList(
    val range: MutableMap<RangeKey, ChangedData> = mutableMapOf(),
    val para: MutableSet<Para> = mutableSetOf()
)
data class Para(
    val start: Int,
    val end: Int
)
data class ChangedData(
    var name: String = "",
    var age: Long
)
data class RangeKey(
    val start: Int,
    val end: Int
)
fun add(data: TestSetList) {
    val cd = ChangedData("naser", 26)
    data.range[RangeKey(0, 0)] = cd
    data.range[RangeKey(1, 2)] = cd
    data.range[RangeKey(1, 5)] = cd
    data.range[RangeKey(2, 2)] = cd
    data.range[RangeKey(3, 3)] = cd
}
fun change(data: TestSetList) {
    // simulate some change in the process .
    data.range.forEach { (k,v) -> v.name = k.start.toString() }
}
fun delete(data: TestSetList) {
    data.range.keys.filter { it.start == it.end }.forEach { data.range.remove(it) }
}
1
🙌 1
i
@Michael de Kaste is spot on, your change messes up the
Set
equality. Behind the scenes, Set is expressed as keys in a Map
Copy code
public boolean remove(Object o) {
        return map.remove(o)==PRESENT;
}
m
on last addendum:
Copy code
fun add(data: TestSetList) {
    val cd = ChangedData("naser", 26)
    data.range[RangeKey(0, 0)] = cd.copy()
    data.range[RangeKey(1, 2)] = cd.copy()
    data.range[RangeKey(1, 5)] = cd.copy()
    data.range[RangeKey(2, 2)] = cd.copy()
    data.range[RangeKey(3, 3)] = cd.copy()
}
consider using different actual classes as a value for your keys, otherwise the 5 keys will all point to the same value at which point
Copy code
fun change(data: TestSetList) {
    // simulate some change in the process .
    data.range.forEach { (k,v) -> v.name = k.start.toString() }
}
does nothing but changes the name of the value on all keys to "3"
❤️ 1
a
thanks a lot..