Objects Comparison based on Property

Hi Folks, I’m currently on the development of a text based App for children affected by speech disorder.

  1. INTRODUCTION - Please skip this if you are interested in technical aspects only

Essentially the App allows the operator to convert a text into images when typing into a TextField, all that is based on a SQLite association table that points to the current image path/name.png.

I’m actually able to retrieve the image / word and Dinamically add them into a CanvasContainer whenever an association is found in the SQLite database (pretty similar to the achieved result of Example Projects / ObjectsInCanvas)

When I delete a word, ever the last…

2 ) TECHNICAL ASPECTS - The Real Matter

I need to compare mCanvasObjects(i).Properties to determine which CanvasObject I should remove.

I partially obtained a working result filtering mCanvasObjects(i).Property with Property = Caption but when a duplicated Object Property matches I also need to compare mCavasObjects(i).Property where Property = Left and mCanvasObject(i).Left > mCanvasObject(i).Left.

I’m struggling trying to understand how to compare the two or more Object which remain after Caption = DeletedWord Filter.

Here my Live Code I’m testing for this function to be achieved.

Thank you for any support on this.

    For i As Integer = DisplayBox.mCanvasObjects.LastIndex DownTo 0 Step 1
      
      If DisplayBox.mCanvasObjects(i).Caption = LastWordCanc Then
        
        // This Will Remove The Canvas Option 1

        // But how to manage If DisplayBox.mCanvasObjects.RemoveAt(i) while i is still an array?

        // If 2 or more Objects I would like to remove the DB.mCanvasObjects(i)Left while Left is the Greatest Value
        
        DisplayBox.mCanvasObjects.RemoveAt(i)
        
       ElseIf DisplayBox.mCanvasObjects(i).Caption = LastWordAdd Then
        
        // This Will Remove The Canvas Option 2
        
        DisplayBox.mCanvasObjects.RemoveAt(i)
        
      End If
      
    Next

I notice a couple of things:

  1. Whenever removing objects from an array in a loop, you need to loop backwards.
  2. You should be using [If … ElseIf … End If] instead of two [If Then … End If].
1 Like

Thank You Aaron, I just corrected the code implementing your precious suggestions.

I went back and read your explanation, but it’s not entirely clear what you’re trying to do. In your code, both of your If Thens do the same thing (remove an item) in which case you can simply use “or” and one If … then block instead of ElseIf and two blocks.

It sounds like your issue is “how does one distinguish between objects in an array”? If the objects are ordered, you just use the indexes, easy. If you don’t know the order, instead of comparing properties of the objects, what one normally would try to do is to work with references to the objects themselves. If you can’t do that, another strategy is to give each object a unique ID and track those. If you’re creating the objects from a DB, then each lookup already has a unique ID you can assign to the object. If you look up the same thing multiple times, you can enumerate each one, or append System.microseconds, etc. or use a simple global counter, there are many options.

1 Like

Again, precious hint by you Aaron, and sorry if the explanation is not even clear to you, probably it’s my fault.

Atctually you shoud not consider the option 2, because the funcion of Object Comparison does not depend by it, it’s only a strategy to manage the method in two different cases but it should be considered as the same at the same time.

The Fact is that the Index changes when I move Objects around the Container (BringToFront Function).

In each case I want always to be removed the object that is next to the right.

So please refer to the following code to get the real idea of what I need to achieve.

    For i As Integer = DisplayBox.mCanvasObjects.LastIndex DownTo 0 Step 1
      
      If DisplayBox.mCanvasObjects(i).Caption = LastWordCanc Then
        
        Var x As String = DisplayBox.mCanvasObjects(i).Caption()
        
        Var y As Integer = x.Count
        
        If y > 1 Then
          
          MessageBox("Yes, you still need to manage this case")
          
          // Determine now which DisplayBox.mCanvasObjects(i).Left() Is The Greatest
          // And then Remove it
          
          DisplayBox.mCanvasObjects.RemoveAt(i)
          
        End If

      End If
      
    Next

Okay, although these seem to be a basic design flaw here, let’s handle this specific case:

You want to match a given string, and a greatest value, checking all objects in an array.

Here’s how you could do that, if you haven’t designed it to be simpler.

var j, indexes(), lefts() as integer
for j = 0 to DisplayBox.mCanvasObjects.Ubound
  if DisplayBox.mCanvasObjects(j).Caption = stringToMatch then
    indexes.add j
    lefts.add DisplayBox.mCanvasObjects(j).left
  end if
next

' sort the matches according to the .left property
lefts.sortWith( indexes() )

' remove the one with the greatest value
DisplayBox.mCanvasObjects.remove( indexes( lefts.Ubound ) )
1 Like

Not sure, but shouldn’t it be “Step -1”? Or just remove “Step” altogether, as -1 is the default for “DownTo”.

Also, are you trying to remove multiple objects? If not, the direction of the loop doesn’t matter.

1 Like

Aaron was absolutely right (Tested). Step 1 Is Optional I know and it Must be Positive when used in combination with DownTo, it’s optional, true but… Why not?

You know Aaron you make me think that knowledge is always the key of success, I’m a newby and I never encountered the " Ubound " function before: let me study about it and then I will be back to you to confirm, anyway I think it’s the key of the solution to my question.

( I previously tried Max(x, x) without success)

For the moment, let me just thank you for your hints. Really appreciated.

Glad to help. Since you are just starting, you will probably want to use the new API: Array.LastRowIndex (which is the same as the old API I’m still using: Array.Ubound)

1 Like

Wonderful, your code design has been resolutive in my case, probably this was not a difficult result to achieve so I will take some further time to study how you achieved the solution exploiting your own knoledge ( as I would never been able to do so ).

Basically If I’m not wrong you dinamically created an array for Objects* comparison and that’s what I didn’t know I could do.

Thank you very much Aaron, you found the solution!

Yes, it often happens that you want to sort an array of objects by one of their properties, and this how to do that. I could have put some comments in the first part of the code to help you understand.

// match caption for object in array with highest .left value
' for each match, we store the index in an indexes() array,
' and we store the .left value in a lefts() array,
' then we sort both arrays by the .left values, 
' so the last element in indexes() will be our target

Once you know how the array functions .add and .sortWith() work, the code will make perfect sense.

1 Like

Absolutely right Aaron!

LastRowIndex was deprecated in favor of LastIndex in the latest versions.