Android Question resort CLV items correct way

Addo

Well-Known Member
Licensed User
Longtime User
hello everyone , i am trying to resort clv items using the following method


firts i created a List and added it to CLV then i resort some items in that list and at last i remove the sorted item from clv and insert it again at its new position . all works well , until i do sort multiable items then the clv start to repeat the items.

obviously i am doing it wrong

here is what i did

B4X:
Public Sub SORTCLVITEM(nametofind As String)

Dim namenum() As String = Regex.Split("\~", nametofind)
Dim itemtosort1 As String
Dim itemtosort2 As String



'remove item from clv based on parameter number and adjusting its sorting
For i = 0 To Persons.Size - 1
Dim usr As Person
usr = Persons.Get(i)
If usr.userid = namenum(2) Then
usr.sortnumber = 1
usrlist.RemoveAt(i)
Exit
End If
Next

'remove and sort other item based on media1 that equal to yes
For g = 0 To Persons.Size - 1
Dim usr As Person
usr = Persons.Get(g)

If usr.media1 = "YES" Then
usr.sortnumber = 2
usr.media1 = "NO"
itemtosort1 = usr.userid ' i just added this variabl to insert later at its order

usrlist.RemoveAt(g)
Exit
End If
Next



'remove and sort other item based on media2 that equal to yes
For u = 0 To Persons.Size - 1
Dim usr As Person
usr = Persons.Get(u)

If usr.media2 = "YES" Then
usr.sortnumber = 3
usr.media2 = "NO"
itemtosort2 = usr.userid ' i just added this variable to insert it later at its order

usrlist.RemoveAt(u)
Exit
End If
Next


Persons.SortType("sortnumber", True) ' here start to sort



' start inserting the removed items based on parameter and variable to resort
   

For k = 0 To Persons.Size - 1
Dim usr As Person
Dim itmheigh As Int
usr = Persons.Get(k)

If usr.userid = namenum(2) Then ' parameter item to add

usrlist.InsertAt(k, Createuserafterclearlist(usr.cusername, usrlist.AsView.Width, 60dip), usr.cusername)

End If

If usr.userid = itemtosort1 Then ' sorted item1 to add


usrlist.InsertAt(k, Createuserafterclearlist(usr.cusername, usrlist.AsView.Width, 60dip), usr.cusername)



End If


If usr.userid = itemtosort2 Then 'sorted item2 to add
   
usrlist.InsertAt(k, Createuserafterclearlist(usr.cusername, usrlist.AsView.Width, 60dip), usr.cusername)

End If

Next


End Sub


when clv have about 100 items the reinserted items gets duplicated like inserted twice , what is the correct way to sort in this case ?
 

OliverA

Expert
Licensed User
Longtime User
There is some issues with your code that may have no relation to the double entries of you CLV, they are issues nontheless. Let's look at just one fragment (this is repeated several times in your code with some slight changes):

B4X:
For i = 0 To Persons.Size - 1
Dim usr As Person
usr = Persons.Get(i)
If usr.userid = namenum(2) Then
usr.sortnumber = 1
usrlist.RemoveAt(i)
Exit
End If
Next
Issue#1:
It's amazing this code has not thrown an error for you yet. Every time you remove an item from a list, the size changes and therefore the upper index becomes one less.
Example code that shows the issue (it will throw an error)
B4X:
Dim l As List
l.Initialize
For x = 1 To 10
    l.Add(x)
Next
l.RemoveAt(8)
l.RemoveAt(9)
and error displayed:
java.lang.IndexOutOfBoundsException: Index: 9, Size: 9
So before calling l.RemoveAt(8), the size of the list is 10 items, with the largest index being 9 (indexes are 0 based, so in this case, the valid index numbers are 0-9). After calling l.RemvoeAt(8), the size of the list is only 10 items and the valid index ranges are 0-8, therefore and index of 9 will produce the error posted.

Issue#2:
Because the list resizes, the indexes do not match up anymore between two lists. Code time:
B4X:
    Dim l As List
   l.Initialize
   For x = 0 To 9
       l.Add(x)
   Next
   Dim l2 As List
   l2.Initialize
   For x = 0 To 9
       l2.Add(x)
   Next
   For x = 0 To l.Size -1
       Dim y As Int
       y = l.Get(x)
       If y > 3 And y < 6 Then
           l2.RemoveAt(x)
       End If
   Next
   
   For x = 0 To l2.Size - 1
       Log(l2.Get(x))
   Next
Looking at your code, you probably expect this output
B4X:
0
1
2
3
6
7
8
9
but you are really getting this
B4X:
0
1
2
3
5
7
8
9
Why? Think about it. When l.Get(4) returns 4, we satisfy the If condition and perform l2.RemoveAt(4). That remove's the fifth element of l2, which contains a 4. Ok. Good so far. The problem is that now the sixth element, the number 5 now becomes the new fifth element and the seventh element, the number 6 becomes the new sixth element and so on. No l.Get(5) returns a 5. It meets the if condition. We call l2.RemoveAt(5), removing the sixth element of l2. Well, the sixth element is the number 6 and we remove it. As before, all the elements above move one down.(BTW, this code still suffers from issue#1).

How to solve this? When working with lists and removing items, work from the top of the list to the bottom:
B4X:
    Dim l As List
   l.Initialize
   For x = 0 To 9
       l.Add(x)
   Next
   Dim l2 As List
   l2.Initialize
   For x = 0 To 9
       l2.Add(x)
   Next
   'Work the list from top to bottom!
   For x = l.Size -1 To 0 Step -1
       Dim y As Int
       y = l.Get(x)
       If y > 3 And y < 6 Then
           l2.RemoveAt(x)
       End If
   Next
   
   For x = 0 To l2.Size - 1
       Log(l2.Get(x))
   Next
Output:
B4X:
0
1
2
3
6
7
8
9

Apologies for the long explanation, maybe I could have said it shorter, but I thought some code examples would bring home the point. Now that I look at it, I'm pretty sure that is why you are getting duplicate entries (since the wrong items are being deleted out of your userlist list).
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Issue#3: Due to the resizing of userlist, you cannot do 3 separate comparison runs between Persons and userlist. Also, before you start the comparison and remove items from userlist, userlist must be a copy of Persons. So
Pseudo code:
B4X:
Make a copy of Persons to userlist
Step through Persons list from top to bottom:
  removeFlag = false
  If condition# 1 is met then removeFlag = True
  If condition# 2 is met then remvoeFlag = True
  ...
  If condition# x is met then removeFlag = True
 
  If removeFlag = True Then remove item from userlist
Next
Empty CLV
use userlist to repopulate CLV
 
Upvote 0

OliverA

Expert
Licensed User
Longtime User
Persons.SortType("sortnumber", True) ' here start to sort
Tell you the truth, I'm lost from this point on. So far, we created a new list that had a bunch of items removed due to some criteria. Now you are sorting Persons and then adding items back into the userlist from Persons at certain positions (k) that don't quite mach up anymore (userlist has most likely less items since Persons, since we were removing stuff). So why are we now adding items back in? The more I look at it, I'm going with post#2 by @Erel.
 
Upvote 0

Addo

Well-Known Member
Licensed User
Longtime User
Hello oliver, userlist is A customlistview control not a list , the removing and re adding done to the customlistview to change its position, i will go with clear the whole clv and adding it again

note maybe i did not describe good enough from where userlist get its items.
 
Upvote 0
Top