B4J Question How to iterate through a list when the list size is unknown

LucaMs

Expert
Licensed User
simply:
B4X:
For a = 0 to myList.Size -1
(Step 1 is implied).



The Step can be used if you wanted to do different steps, by 2 or 3.

"Step -1" can be used so:

B4X:
For a = myList.Size -1 to 0 Step -1
 

giga

Well-Known Member
Licensed User
Thanks for the reply.
B4X:
For a = myList.Size -1 to 0 Step -1
Did solve the outofbounds exception. But Maybe I am using the wrong structure. If Step is set to -1 it returns ALL the IDs. If I step it to 2 it will show the first then every other one.

My ultimate goal is to step the IDs "one by one" Is that possible using step? Or is there a better way?
 

giga

Well-Known Member
Licensed User
Thanks for the replies. Here's what I am trying to do.

All the lists are of various sizes. Some lists may have 4 ids others may have 10 ids etc...

I can iterate through any of the list but the problem is (since I don't always know the size of the list) If I go beyond the size of the list it errors.OutOfBounds Exception(Understandably)

example error when there are 4 ids.(logging them individually)

B4X:
Log(id(1))
Log(id(2))
Log(id(3))
Log(id(4))
Log(id(5)) 'It will error here and beyond because there is no 5......

Next
My thought was to step the list by 1 until I reached the end of the list. Thinking it would allow me to retrieve each individual id (i.e Log(id(3)) without going outofbounds (if the list was 3 or less). But that doesn't seem to be right.

Thanks for sticking with me.:)
 

LucaMs

Expert
Licensed User
your id seems to be an Array, not a List.

If you have:
B4X:
lstID As List
and you added the IDs:
B4X:
lstID.Add(5)
lstID.Add(53)
lstID.Add(11)
lstID.Add(2343)
lstID.Add(22)
then you can iterate:
B4X:
For Each ID As Int In lstID
    Log(ID)
Next
or

B4X:
For I = 0 to lstID.Size - 1
    Log(lstID.Get(I))
Next

[P.S. its name should be lstIDs, but I did not want to change everything :D]



If you use an Array, you should have:
Dim IDs(5) As Int
and you will have 5 "locations" but indexed from 0 to 4.
Log(IDs(0)) ' ok
Log(IDs(1)) ' ok
...
Log(IDs(4)) ' ok
Log(IDs(5)) ' out of bound

or

B4X:
For I = 0 to IDs.Lenght - 1
    Log(IDs(I))
Next
 
Last edited:

giga

Well-Known Member
Licensed User
LucasMs. ( Thanks Your response could not have been any faster:))

This is the code I am working with:
B4X:
Dim parser As JSONParser
    parser.Initialize(str)
    Dim root As Map = parser.NextObject
    Dim myList As List = root.Get("myList")
    Dim resSize As Int = myList.size
    Dim id(resSize),vote_count(resSize) As Int
    Dim vote_average(resSize) As Double
    Dim title(resSize), release_date(resSize), original_title(resSize),video(resSize) As String
    Dim c As Int = 0
    For Each colresults As Map In myList
     id(c) = colresults.Get("id")
     title(c) = colresults.Get("title")
     vote_average(c) = colresults.Get("vote_average")
     release_date(c) = colresults.Get("release_date")
     original_title(c) = colresults.Get("original_title")
     vote_count(c) = colresults.Get("vote_count")
     video(c) = colresults.Get("video")
    c = c + 1
    Next
    For a = 0 To myList.Size -1
    Log("record: " & a)
        Log (id(a))
       Log (title(a))
       Log (vote_average(a))
       Log (release_date(a))
       Log (original_title(a))
       Log (vote_count(a))
       Log (video(a))
        Log("-----------------------" & CRLF)
    Next
Log(id(a) will retrieve ALL the IDS.

But let's say I want ONLY id 4 not knowing if id 4 exists will throw error outofbounds. That's my problem.

How do I retrieve each id(1), id(2) etc... individually without knowing what the last Id is and running into the outofbound error?
 
Last edited:

LucaMs

Expert
Licensed User
LucasMs. ( Thanks Your response could not have been any faster:))

This is the code I am working with:
B4X:
Dim parser As JSONParser
    parser.Initialize(str)
    Dim root As Map = parser.NextObject
    Dim myList As List = root.Get("myList")
    Dim resSize As Int = myList.size
    Dim id(resSize),vote_count(resSize) As Int
    Dim vote_average(resSize) As Double
    Dim title(resSize), release_date(resSize), original_title(resSize),video(resSize) As String
    Dim c As Int = 0
    For Each colresults As Map In myList
     id(c) = colresults.Get("id")
     title(c) = colresults.Get("title")
     vote_average(c) = colresults.Get("vote_average")
     release_date(c) = colresults.Get("release_date")
     original_title(c) = colresults.Get("original_title")
     vote_count(c) = colresults.Get("vote_count")
     video(c) = colresults.Get("video")
    c = c + 1
    Next
    For a = 0 To myList.Size -1
    Log("record: " & a)
        Log (id(a))
       Log (title(a))
       Log (vote_average(a))
       Log (release_date(a))
       Log (original_title(a))
       Log (vote_count(a))
       Log (video(a))
        Log("-----------------------" & CRLF)
    Next
Log(id(a) will retrieve ALL the IDS.

But let's say I want ONLY id 4 not knowing if id 4 exists will throw error outofbounds. That's my problem.

How do I retrieve each id(1), id(2) etc... individually without knowing what the last Id is and running into the outofbound error?

If your code is correct (I don't know JSONparser):
Dim resSize As Int = myList.size
Dim id(resSize),vote_count(resSize) As Int
you know the max index you can use, resSize-1 (or myList.Size -1, it is the same).

(Perhaps I have not understood the question :D)
 

giga

Well-Known Member
Licensed User
No problem, Thanks anyway.:) Where I am struggling is my list could be any number of id's. I can iterate ALL id's no matter how big the list.

But how do I retrieve only one id out of the list(without knowing the total number of id's) in the list without running into the outofbounds.exception.

Maybe a conditional statement to catch the end of the total id's to avoid the exception ??
 

LucaMs

Expert
Licensed User
You could use try-catch but... if you have a List, you know how many items it has!

If you need the fourth item (index 3):

B4X:
If MyList.Size >= 4 Then
   FoundID = MyList.Get(3)
' or, as in your example:
   FoundID = ID(3)
End IF

Last try :D:

MyList.IndexOf is a function of List; it returns -1 if the item is not found
 

jmon

Well-Known Member
Licensed User
what you need to do if you have to do it with a single loop is this :
B4X:
For a = 0 To myList.Size -1
    Log("record: " & a)
    If id.size > a then Log (id(a))
    If title.size > a then Log (title(a))
    If vote_average.size > a then Log (vote_average(a))
    If release_date.size > a then Log (release_date(a))
    If original_title.size > a then Log (original_title(a))
    If vote_count.size > a then Log (vote_count(a))
    If video.size > a then Log (video(a))
    Log("-----------------------" & CRLF)
Next
 

LucaMs

Expert
Licensed User
what you need to do if you have to do it with a single loop is this :
B4X:
For a = 0 To myList.Size -1
    Log("record: " & a)
    If id.size > a then Log (id(a))
    If title.size > a then Log (title(a))
    If vote_average.size > a then Log (vote_average(a))
    If release_date.size > a then Log (release_date(a))
    If original_title.size > a then Log (original_title(a))
    If vote_count.size > a then Log (vote_count(a))
    If video.size > a then Log (video(a))
    Log("-----------------------" & CRLF)
Next

He sized all arrays the same length (resSize = myList.Size) #7
 

giga

Well-Known Member
Licensed User
You could use try-catch but... if you have a List, you know how many items it has!

If you need the fourth item (index 3):

B4X:
If MyList.Size >= 4 Then
   FoundID = MyList.Get(3)
' or, as in your example:
   FoundID = ID(3)
End IF

Last try :D:

MyList.IndexOf is a function of List; it returns -1 if the item is not found
@LucaMs @jmon
I found a workaround not sure if I should release it like this but this works for me. I am using a try-catch then log. I am downloading a json file that has different numbers of ids.
This will check each id 0-25 and if the id has no content it will log (id is empty)

B4X:
Try
    If id(0) >= a Then Log(id(0))
    If id(1) >= a Then Log(id(1))
    If id(2) >= a Then Log(id(2))
    If id(3) >= a Then Log(id(3))
    If id(4) >= a Then Log(id(4))
    If id(5) >= a Then Log(id(5))
    If id(6) >= a Then Log(id(6))
    If id(7) >= a Then Log(id(7))
    If id(8) >= a Then Log(id(8))
    If id(9) >= a Then Log(id(9))
    If id(10) >= a Then Log(id(10))
    If id(11) >= a Then Log(id(11))
    If id(12) >= a Then Log(id(12))
    If id(13) >= a Then Log(id(13))
    If id(14) >= a Then Log(id(14))
    If id(15) >= a Then Log(id(15))
    If id(16) >= a Then Log(id(16))
    If id(17) >= a Then Log(id(17))
    If id(18) >= a Then Log(id(18))
    If id(19) >= a Then Log(id(19))
    If id(20) >= a Then Log(id(20))
    If id(21) >= a Then Log(id(21))
    If id(22) >= a Then Log(id(22))
    If id(23) >= a Then Log(id(23))
    If id(24) >= a Then Log(id(24))
    If id(25) >= a Then Log(id(25))
  Catch
  Log("id is empty")
 
End Try
Thanks for all the help. If there's a better way I am open to suggestions.
 

LucaMs

Expert
Licensed User
Sorry, I don't understand.

Dim parser As JSONParser
parser.Initialize(str)
Dim root As Map = parser.NextObject
Dim myList As List = root.Get("myList")
Dim resSize As Int = myList.size
Dim id(resSize),vote_count(resSize) As Int
Dim vote_average(resSize) As Double
Dim title(resSize), release_date(resSize), original_title(resSize),video(resSize) As String
Dim c As Int = 0
For Each colresults As Map In myList
id(c) = colresults.Get("id")
title(c) = colresults.Get(
"title")
vote_average(c) = colresults.Get(
"vote_average")
release_date(c) = colresults.Get(
"release_date")
original_title(c) = colresults.Get(
"original_title")
vote_count(c) = colresults.Get(
"vote_count")
video(c) = colresults.Get(
"video")
c = c +
1
Next

The code above (your code) works?

If so, you know that you will have id(0) to id(resSize - 1)
Or you can check id.Length
If id.Length will be = 10, I'm sure that you will not have id(10), id(11), ...!
 
Last edited:

giga

Well-Known Member
Licensed User
Sorry, I don't understand.




The code above (your code) works?

If so, you know that you will have id(0) to id(resSize - 1)
Or you can check id.Lenght
If id.Lenght will be = 10, I'm sure that you will not have id(10), id(11), ...!

You are absolutely right! "If id.Lenght will be = 10, I'm sure that you will not have id(10), id(11), ...!"
But the user(s) don't know how many ids there are in the list and if they select id(11) the error outofbounds appears.

Scenario.
1. I download a json file (this particular one only has 4ids in it).
2. I set the code length to 10 or 25 even
3. The user is not aware how many ids are in the list and chooses to pull up id(11)
4. This will produce the outofbounds error because there is no 11



The only way I can stop the error is by try-catch.

in my example code above my list has 23ids in it.(25 is my maximum length )any id 23 and below will show the contents, If the user selects number 24 or 25. it will show (id is empty)
 

LucaMs

Expert
Licensed User
But the user(s) don't know how many ids there are in the list and if they select id(11)
How they "select" the id?

You fill some view (ListView? Other?) with the IDs! Create only id.Length items!


[If they enter the number in an EditText, validate the input inside of EditText_TextChanged, of course]
 

LucaMs

Expert
Licensed User
(I would avoid things like: id(gotonum.Text). Dim GoToNum As Int and then GoToNum = gotonum.text is better).

I suppose that gotonum.Text is where the user "selects" the index of id and IDText.Text shows the choice (a label would be better).

You need to validate gotonum.Text value, inside of gotonum_TextChanged or gotonum_FocusChanged or elsewhere, before set IDText.Text = id(GoToNum).


[P.S. validate: I mean: If GoToNum > id.Length-1 then ... not valid]
 

giga

Well-Known Member
Licensed User
(I would avoid things like: id(gotonum.Text). Dim GoToNum As Int and then GoToNum = gotonum.text is better).

I suppose that gotonum.Text is where the user "selects" the index of id and IDText.Text shows the choice (a label would be better).

You need to validate gotonum.Text value, inside of gotonum_TextChanged or gotonum_FocusChanged or elsewhere, before set IDText.Text = id(GoToNum).


[P.S. validate: I mean: If GoToNum > id.Length-1 then ... not valid]
Good advice.

As they say "back to the drawing board" You're Awesome for all the help. I will make the changes and see how that works:).
 
Top