Problem using the example-file in collections-lib

moster67

Expert
Licensed User
Longtime User
Hi,

I wanted to try out Agraham's updated Collection-library but the demofile (the included source-code) won't load in Basic4PPC (6.30).

I get a message saying "This file is from a newer version and it may run improperly. Please check for an updated version....."

I guess that this is maybe because Agraham is using the new beta-version. Any chance one can still download the old version of the library? I'm mainly interested in trying out the Hashtable which I think was included also in the old library.

Thank you.

moster67
 

Erel

B4X founder
Staff member
Licensed User
Longtime User
The new version should be released in a few weeks...

For now this is the code of CollectionsTest (don't forget to add the objects):
B4X:
Sub Globals
    'Declare the global variables here.
    Dim TestArray1(0)
    Dim TestArray2(0) 
End Sub

Sub App_Start
    'Form1.Show
    Stack.New1
    Queue.New1
    Hash.New1
    Sorted.New1
    Msgbox("Collections library version " & Stack.Dllversion)
    Stack_Test
    Queue_Test
    Hash_Test
    Sorted_Test
End Sub

Sub ShowTestArray(list)
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & TestArray1(i) & " "
    Next
    Msgbox(msg,list)
End Sub

Sub Stack_Test
    Stack.Push("fred")
    Stack.Push("2.2")
    Stack.Push(True)
    Stack.Push(53)
    Msgbox("Stack contains 53 is " & Stack.Contains(53),"Stack")
    Testarray1() = Stack.ToArray
    msg = "Stack.ToArray" & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & TestArray1(i) & CRLF
    Next
    Msgbox(msg,"Stack")    
    msg = "Stack.Count is " & Stack.Count & CRLF & "Stack.Peek is " & Stack.Peek & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & Stack.Pop & CRLF
    Next    
    Msgbox(msg, "Stack")    
End Sub

Sub Queue_Test
    Queue.Enqueue("1")
    Queue.Enqueue(2)
    Queue.Enqueue("3")
    Queue.Enqueue(True)
    Msgbox("Queue contains 3 is " & Queue.Contains(3),"Queue")
    TestArray1() = Queue.ToArray
    msg = "Queue.ToArray" & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & TestArray1(i) & CRLF
    Next
    Msgbox(msg,"Queue")    
    msg = "Queue.Count is " & Queue.Count & CRLF & "Queue.Peek is " & Queue.Peek & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & Queue.Dequeue & CRLF
    Next    
    Msgbox(msg, "Queue")    
End Sub

Sub Hash_Test
    Hash.Add("a","fred")
    Hash.Add("b","jim")
    Hash.Add("c","bill")
    Hash.Add(10,"charlie")
    Hash.Add(15,"paul")
    Hash.Add(23,"mick")
    Msgbox("Count is " & Hash.Count & CRLF & " Hash contains key 'c' is " & Hash.ContainsKey("c") & ", value is '" &  Hash.Item("c") & "'", "HashTable")
    Msgbox("Count is " & Hash.Count & CRLF & " Hash contains value 'paul' is " & Hash.ContainsValue("paul"), "HashTable")
    testArray1() = Hash.ToArrayKeys
    testArray2() = Hash.ToArrayValues
    msg = "HashTable.ToArrays" & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & TestArray1(i) & Chr(9) & TestArray2(i) & CRLF
    Next
    Msgbox(msg,"HashTable")        
End Sub

Sub Sorted_Test
    Sorted.Add(15,"paul")
    Sorted.Add("c","bill")
    Sorted.Add(10,"charlie")
    Sorted.Add("a","fred")
    Sorted.Add(23,"mick")
    Sorted.Add("b","jim")
    Msgbox("Count is " & Sorted.Count & CRLF & " Sorted contains key 'c' is " & Sorted.ContainsKey("c") & ", value is '" &  Sorted.Item("c") & "'", "SortedList")
    Msgbox("Count is " & Sorted.Count & CRLF & " Sorted contains value 'paul' is " & Sorted.ContainsValue("paul"), "SortedList")
    Msgbox("Index of key 'c' is " & Sorted.IndexOfKey("c"), "SortedList")
    Msgbox("Index of value 'fred' is " & Sorted.IndexOfValue("fred"), "SortedList")
    Msgbox("Key and value at 4 are " & Sorted.GetKeyAt(4) & " & " & Sorted.GetValueAt(4), "SortedList")
    TestArray1() = Sorted.ToArrayKeys
    testArray2() = Sorted.ToArrayValues
    msg = "SortedTable.ToArrays" & CRLF & CRLF
    For i = 0 To ArrayLen(TestArray1())-1
        msg = msg & TestArray1(i) & Chr(9) & TestArray2(i) & CRLF
    Next
    Msgbox(msg,"SortedList")
End Sub

ArrayExDemo:
B4X:
Sub Globals
    'Declare the global variables here.
    Dim a(0) 
    Dim b(0)

End Sub

Sub App_Start
    'Form1.Show
    ArraysEx.New1
    AddArrayList("ArrayList1")
    ArrayListsEx.New1("ArrayList1", B4PObject(1))
    
    AlAddArray
    AlBinarySearch
    AlCopyTo
    AlRemoveRange
    AlReverse
    AlSort
    AlToArray
    
    BinarySearch
    Clear
    Clone
    IndexOf
    LastIndexOf
    Rank
    Reverse
    Sort
    SortKeysAndItems
End Sub

Sub AlAddArray
    ArrayList1.Clear
    len = 10
    Dim a(len)
    For i = 0 To len - 1
        a(i) = i
        msg = msg & i & " "
    Next
    msg = msg & CRLF
    ArrayListsEx.AddArray(a())
    For i = 0 To len - 1        
        msg = msg & ArrayList1.Item(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.AddArray")
End Sub

Sub AlBinarySearch
    ArrayList1.Clear
    len = 10
    For i = 0 To len - 1
        ArrayList1.add(i * 10 + i)
        msg = msg & ArrayList1.Item(i) & " "
    Next
    msg = msg & CRLF
    val = 66
    i = ArrayListsEx.BinarySearch(0, len, val, cNumbers) 
    Msgbox(msg & "Index of " & val & " is " & i, "ArrayListsEx.BinarySearch")
End Sub


Sub AlCopyTo
    ArrayList1.Clear
    len = 10
    Dim a(len)
    For i = 0 To len - 1
        ArrayList1.add(i)
        msg = msg & ArrayList1.Item(i) & " "
    Next
    msg = msg & CRLF
    ArrayListsEx.CopyTo(0, a(), 0, len)
    For i = 0 To len - 1        
        msg = msg & a(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.CopyTo")
End Sub

Sub AlRemoveRange
    ArrayList1.Clear
    len = 10
    Dim a(len)
    For i = 0 To len - 1
        ArrayList1.add(i)
        msg = msg & ArrayList1.Item(i) & " "
    Next
    msg = msg & CRLF
    ArrayListsEx.RemoveRange(3, 5)
    For i = 0 To ArrayList1.Count - 1        
        msg = msg & ArrayList1.Item(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.RemoveRange")
End Sub

Sub AlReverse
    ArrayList1.Clear
    len = 10
    For i = 0 To len - 1
        ArrayList1.Add(i)
        msg = msg & ArrayList1.Item(i) & " "
    Next
    msg = msg & CRLF
    ArrayListsEx.Reverse(5, 5)
    For i = 0 To len - 1
        msg = msg & ArrayList1.Item(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.Reverse")
End Sub

Sub AlSort
    ArrayList1.Clear
    len = 10
    Dim a(0) 
    a() = Array ( "a", "x", "G",  "c", "X", "A", "g", "C", "u", "U" )
    For i = 0 To len - 1
        ArrayList1.Add(a(i))
    Next    
    msg = msg & CRLF
  ArrayListsEx.Sort(0, len, cCaseSensitive)    
    'ArraysEx.Sort(a(),0, len, cCaseUnsensitive)
    For i = 0 To len - 1
        msg = msg &    ArrayList1.Item(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.Sort") 
End Sub

Sub AlToArray
    ArrayList1.Clear
    len = 10
    Dim a(len)
    Dim b(0) 
    For i = 0 To len - 1
        ArrayList1.add(i)
        msg = msg & ArrayList1.Item(i) & " "
    Next
    msg = msg & CRLF
    b() = ArrayListsEx.ToArray
    For i = 0 To len - 1        
        msg = msg & b(i) & " "
    Next
    Msgbox(msg, "ArrayListsEx.ToArray")
End Sub


Sub BinarySearch
    Dim a(10)
    len = ArrayLen(a())
    For i = 0 To len - 1
        a(i) = i * 10 + i
        msg = msg & a(i) & " "
    Next
    msg = msg & CRLF
    val = 66
    i = ArraysEx.BinarySearch(a(), 0, len, val, cNumbers) 
    Msgbox(msg & "Index of " & val & " is " & i, "ArraysEx.BinarySearch")
End Sub

Sub Clear
    Dim a(10) 
    len = ArrayLen(a())
    For i = 0 To len - 1
        a(i) = i
        msg = msg & a(i) & " "
    Next
    msg = msg & CRLF
    ArraysEx.Clear(a(),3,6)
    For i = 0 To len - 1
        If a(i) = "" Then
            msg = msg & "0 "
        Else
            msg = msg & a(i) & " "
        End If
    Next
    Msgbox(msg, "ArraysEx.Clear")
End Sub

Sub Clone
    Dim a(10)
    Dim b(10)
    len = ArrayLen(a())
    For i = 0 To len - 1
        a(i) = i
        msg = msg & a(i) & " "
    Next
    msg = msg & CRLF
    b() = ArraysEx.Clone(a())
    For i = 0 To len - 1
        msg = msg & b(i) & " "
    Next
    Msgbox(msg, "ArraysEx.Clone")
End Sub

Sub IndexOf
    Dim a(10) 
    For i = 0 To ArrayLen(a()) - 1
        a(i) = i Mod 5
        msg = msg & a(i) & " "
    Next
    val = 3
    ix = ArraysEx.IndexOf(a(), val, 0, ArrayLen(a()))
    msg = msg & CRLF & "Index of " & val & " is " & ix 
    Msgbox(msg, "ArraysEx.IndexOf")
End Sub

Sub LastIndexOf
    Dim a(10)
    For i = 0 To ArrayLen(a()) - 1
        a(i) = i Mod 5
        msg = msg & a(i) & " "
    Next
    val = 3
    ix = ArraysEx.LastIndexOf(a(), 3, ArrayLen(a())-1, ArrayLen(a()))
    msg = msg & CRLF & "Last index of " & val & " is " & ix 
    Msgbox(msg, "ArraysEx.LastIndexOf")
End Sub

Sub Rank
    Dim a(3,4,5)
    For i = 1 To ArraysEx.Rank(a())    
        msg = msg & "Rank " & i & " length " & ArrayLen(a(),i) & CRLF
    Next
    msg = msg & "Total length " & ArraysEx.TotalLength(a())
    Msgbox(msg, "ArraysEx.Rank")
End Sub

Sub Reverse
    Dim a(10) 
    len = ArrayLen(a())
    For i = 0 To len - 1
        a(i) = i
        msg = msg & a(i) & " "
    Next
    msg = msg & CRLF
    ArraysEx.Reverse(a(),5, 5)
    For i = 0 To len - 1
        msg = msg & a(i) & " "
    Next
    Msgbox(msg, "ArraysEx.Reverse")
End Sub

Sub Sort
    Dim a(10) 
    len = ArrayLen(a())
    a() = Array ( "a", "x", "G",  "c", "X", "A", "g", "C", "u", "U" )
    msg = msg & CRLF
  ArraysEx.Sort(a(),0, len, cCaseSensitive)    
    'ArraysEx.Sort(a(),0, len, cCaseUnsensitive)
    For i = 0 To len - 1
        msg = msg & a(i) & " "
    Next
    Msgbox(msg, "ArraysEx.Sort") 
End Sub

Sub SortKeysAndItems
    Dim a(10) 
    Dim b(10) 
    len = ArrayLen(a())
    Dim b(10)
    For i = 0 To len - 1
        a(i) = Rnd(33,128)
        j = a(i)        
        b(i) = Chr(a(i))
        msg = msg & a(i)& ":" & b(i) & "  "
    Next
    msg = msg & CRLF
    ArraysEx.SortKeysAndItems(a(), b(), 0, len, cNumbers)
    For i = 0 To len - 1
        msg = msg & a(i)& ":" & b(i) & "  "
    Next
    Msgbox(msg, "ArraysEx.SortKeysAndItems") 
End Sub
 

moster67

Expert
Licensed User
Longtime User
No problem. I am very thankful to you for all your libraries you are furnishing us with along with great examples how to implement them.:sign0188:

BTW: being on the subject of your collection-library......I am just wondering if the key in the Hashtable must be mandatory a string-datatype (as indicated in the help-file). I am asking since I've seen vb.net-code on the Intenet using for instance other data-types such as Int ?

EDIT: I think I got it all wrong - it seems like the key must be a string. In the example I found on the internet, the Int-key is being converted into a string before being added as a key (using .toString). Sorry

rgds,
moster67


Sorry about that :sign0013: I went to great lengths to make sure the ArrayListsEx and other objects in the library would work in previous versions as well as the latest but I overlooked the fact that the B4ppc demo source might not :signOops:
 
Last edited:

agraham

Expert
Licensed User
Longtime User
I am just wondering if the key in the Hashtable must be mandatory a string-datatype (as indicated in the help-file)
Basic4ppc is very weakly typed, which in practice means that everything is a String so as far as Basic4ppc is concerned any value that you can manipulate in a variable can be used as either a key or a value in a hashtable, or other collection, where they will in fact be stored as strings.
 

moster67

Expert
Licensed User
Longtime User
THank you for the clarification - I also found out that key is actually stored as a string (I edited my previous post.)

regards,
moster67
 

agraham

Expert
Licensed User
Longtime User
EDIT: I think I got it all wrong
No, you didn't get it wrong. Hashtable, and the other non-generic collections in .NET, actually store Objects which basically means that you can store anything as in .NET everything, including numerics, are descended from Object. If the VB.NET fragment you found was converting an Int to a string it was for a different reason.

However, as I said before, because Basic4ppc is weakly typed you can regard everything as a String and ignore Types altogether.
 

moster67

Expert
Licensed User
Longtime User
Wow! What a wise man you are! You're like an enciclopedia.

I don't know what you do for a living (probably an expert-programmer for an important company or something similar) but I would love to see you teaching programming in a class-room (unfortunately I can't quit working, I have a family to maintain, but I'd love to be your student in that class-room).

Moster67


No, you didn't get it wrong. Hashtable, and the other non-generic collections in .NET, actually store Objects which basically means that you can store anything as in .NET everything, including numerics, are descended from Object. If the VB.NET fragment you found was converting an Int to a string it was for a different reason.

However, as I said before, because Basic4ppc is weakly typed you can regard everything as a String and ignore Types altogether.
 

agraham

Expert
Licensed User
Longtime User
I don't know what you do for a living
Thanks for the compliments :). I retired early after 35 years in the mini-computer/PC business where I ran hardware and software design teams as well as getting my hands dirty with both. As it happens I DID have a reputation as a good trainer of young engineers.
 

moster67

Expert
Licensed User
Longtime User
I DID have a reputation as a good trainer of young engineers

I'm sure you DID and I'm sure you would STILL be a great trainer/teacher.

Thx again !

rgds,
moster67
 

corwin42

Expert
Licensed User
Longtime User
However, as I said before, because Basic4ppc is weakly typed you can regard everything as a String and ignore Types altogether.

Does this mean that I even can use structure variables as key or value in a hashtable?

I want to port a VB .NET program to B4PPC and after a quick look I saw that there are Points (x- and y-values) stored in a hashtable (with hash.add(p, p), p is declared with Dim p As Point). I wanted to use a structure variable for the Points but I don't know if they can be stored in a hashtable.

Greetings
Markus
 

agraham

Expert
Licensed User
Longtime User
Does this mean that I even can use structure variables as key or value in a hashtable?
No the Hashtable in the Collections library can only accept values as Strings, not references. So individual structure elements may be stored but not a structure. In fact a Basic4ppc structure is actually a two dimensional array and can be referenced as such as well as by the named item syntax.

B4X:
Dim Type(x, y)Point(5) ' structure array of 5 points
  ...
Hash.Add(key, Point(0).x) ' can add a single element

Hash.Add(key, Point(0,0) ' this is the same as the line above

Hash.Add(key, Point(0)) ' this won't work as it is not a value
 

corwin42

Expert
Licensed User
Longtime User
So what is the best way to store an unknown number of distinct Points?

One way I think of is to store them really as strings in a hashtable like

hash.add(p.x & "+" & p.y, p.x & "+" & p.y)

The disadvantage is that I have to decode the string while accessing the values.

I think storing the data in other objects like Arraylist or Table makes no sense because each time I want to insert a new point I have to search the whole list if my item is already present. In a hashtable this is done with hash.contains.

Greetings,
Markus
 

agraham

Expert
Licensed User
Longtime User
So what is the best way to store an unknown number of distinct Points?
It will depend upon several factors such as the the approximate number of points expected, how they are generated, how, and how often, they are needed to be accessed and the speed of access required.

One way I think of is to store them really as strings in a hashtable like
hash.add(p.x & "+" & p.y, p.x & "+" & p.y)
I don't understand how this can work. If you are using a key that is the same as a value then what's the point of using a hashtable as you need to know the result before you can look it up? As an aside if you used ("p.x" & "," & "p.y") then you can split them easily with StrSplit.
 

corwin42

Expert
Licensed User
Longtime User
I don't understand how this can work. If you are using a key that is the same as a value then what's the point of using a hashtable as you need to know the result before you can look it up?

Yes but I don't need to look up a special value. The only reason to use a hashtable is that it is really easy to check if the point is already in the list. Later I will convert the hashtable to an array to access all the values.

The points I want to store are tile coordinates from OpenStreetMap. The program goes along the coordinates of the trackpoints from a gpx file and calculates, which OSM-Tile is needed for this coordinate (this is my "Point"). Then in a second step the program should download all OSM-Tiles in the list.

The bigger problem will be to read the gpx file. Have you seen my other thread in the Wishlist forum?

As an aside if you used ("p.x" & "," & "p.y") then you can split them easily with StrSplit.

Yes, thats a good idea.

Greetings,
Markus
 

agraham

Expert
Licensed User
Longtime User
Later I will convert the hashtable to an array to access all the values.
They will come back out of order from a Hashtable and I would imagine that you want them in the original order if they are trackpoints or waypoints. You might be better adding the points to an 2D Array or Arraylist (or two Arraylists, one each for x and y) as well as to a Hashtable. The Hashtable will tell you if the point exists and at the end you can throw it away and use the Arrays or Arraylist whose points are in the corrct order.
 
Top