Android Question .Put vs .Set

67biscuits

Member
Whilst using a KVS situation to save data, I am trying to determine if like .Set, does .Put overwrite the existing data? Or does one require the use of .Remove prior to updating the entry?

Thanks in advance

Charley
 

67biscuits

Member
Since my edit time ran out whilst trying word the question clearly, I am answering myself with a question. Still open for answers.
Cheers all


Accessing data in a 3 dimensional list, how do I access datum stored in the 3rd level? At said level the datum would be a string or a number, 1st and second levels being lists

I have tried
1stlevel.(2,3)
1stlevel.get(2,3)
1stlevel.get(2.get(3))
but just errors
so far I have dim new list vars and assign the dimensions as I dive for data
eg:

AP.get(Key)

newListVar = AP.get(1) 'to access Journals

newListvar = newListVar.get(2) 'to access 3rd journal entry

log(newListVar.get(2)) 'to access the actual text of the journal


Also, in order to save data, I am trying to determine if like .Set, does .Put overwrite the existing data? Or does one require the use of .Remove prior to update the entry?

Thanks in advance

Charley
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
1. There is no .Set in KVS
2. I never know there is a 3 dimensional List. Do you mean a List "nested" inside another List?

It is better you can upload a small example to show the error so other members can help you.
 
Upvote 0

67biscuits

Member
1. There is no .Set in KVS
2. I never know there is a 3 dimensional List. Do you mean a List "nested" inside another List?

It is better you can upload a small example to show the error so other members can help you.
you are correct, there is no .Set, thus the question, does .Put do as Set does.
And yes the term dimensional is the same as nested. It just indicates how many nests there are.
Sorry, I have no sample code as I am trying to figure this out. The only errors i get are Syntax errors as I type it.(see previous examples of datum extraction)
 
Upvote 0

emexes

Expert
Licensed User
B4X:
newListVar = AP.get(1) 'to access Journals
newListvar = newListVar.get(2) 'to access 3rd journal entry
log(newListVar.get(2)) 'to access the actual text of the journal

This should work, assuming that AP is a list of lists of lists of strings.

Remember that the index (key) starts at 0, not 1. If you only have a single item in a list, then .Get(1) will fail. Use .Get(0) to get the first item.

What does AP stand for? Is it an actual List? Is it stored in memory? What else is stored in it (besides journals)? (there must be something else in it, at AP.Get(0) ie the first list item)

It feels like you're using Lists to ask a question about accessing an online library or database.

Also, why is a journal entry a list of strings (text) rather than just a single string? For example, text files (eg readme.txt) are a single string, containg CRLFs to separate lines and sometimes FFs (ASCII 12 = printer formfeed control code) to separate pages.
 
Last edited:
Upvote 0

aeric

Expert
Licensed User
Longtime User
you are correct, there is no .Set, thus the question, does .Put do as Set does.
And yes the term dimensional is the same as nested. It just indicates how many nests there are.
Sorry, I have no sample code as I am trying to figure this out. The only errors i get are Syntax errors as I type it.(see previous examples of datum extraction)
Using KVS is like you do with Maps, but it persists to a file or reads from a file.

Put
adds a new key and value when the key does not exist;
overwrites the value when the key already exist.

Get
reads the value by the key when the key exists;
returns null when the key does not exist.

Please read the B4X Language guide for Maps and List to understand how they works.

Maybe you should use a Map inside a List instead of using a List inside a List.
e.g
StudentList contains list [ {"name": "Alice", "age": 18}, {"name": "Bob", "age": 21} ]
 
Upvote 0

67biscuits

Member
This should work, assuming that AP is a list of lists of lists of strings.

Remember that the index (key) starts at 0, not 1. If you only have a single item in a list, then .Get(1) will fail. Use .Get(0) to get the first item.

What does AP stand for? Is it an actual List? Is it stored in memory? What else is stored in it (besides journals)? (there must be something else in it, at AP.Get(0) ie the first list item)

It feels like you're using Lists to ask a question about accessing an online library or database.

Also, why is a journal entry a list of strings (text) rather than just a single string? For example, text files (eg readme.txt) are a single string, containg CRLFs to separate lines and sometimes FFs (ASCII 12 = printer formfeed control code) to separate pages.
Ap is a list of lists, of lists, and yes, 0 to size - 1
AP stands for All Projects. One project file contains: customer info, journal entries, hours entries, financial entries, 2 materials entries, required and purchased, and an required equipment list. Each entry to a record is a list. eg, a journal entry has a date, time and a journal entry. An hours entry has a date, start and end times, labour rate, hours etc
AP is a list of lists of list and is stored physically locally as a KVS. I chose not to MAP it as map stores as strings, KVS stores as lists. It eliminated loads of coding.
Specifically, a journal entry, a list of strings, is a date, time and journal entry. 3 separate strings in a list. I could have saved as a single string, as all lists here could be, but down the road, data manipulation reports etc, would be nightmarish.
I've been dealing with multiple dimensional arrays for decades, it's more a question of language than ability.
 
Upvote 0

67biscuits

Member
Using KVS is like you do with Maps, but it persists to a file or reads from a file.

Put
adds a new key and value when the key does not exist;
overwrites the value when the key already exist.

Get
reads the value by the key when the key exists;
returns null when the key does not exist.

Please read the B4X Language guide for Maps and List to understand how they works.

Maybe you should use a Map inside a List instead of using a List inside a List.
e.g
StudentList contains list [ {"name": "Alice", "age": 18}, {"name": "Bob", "age": 21} ]
I starting with a map. But regex'ing everything got discombobulating. KVS saves and retrieves as lists, even lists of lists. Trying to unMAP 3 dimensions, frankly, blew my mind to bits. As the individual entries are set in size, the data is different for all entries, some are editable some are not, so remaking the lists was a daunting task indeed.
My original question, does .Put overwrite like .Set does, seems not to. If I edit a customer record, and save the edit, it creates a new record. I currently .Remove Key and add as I would just as a new record being created. (just noted .Remove(key) doesnt remove the entry. I might be incorrectly saving?)
The other part of the question, not yet answered was how to access a datum three levels down in one line of code. In VB it was: myArray(2,4,3) to access the 4th datum in the 5th record of the third file. I was wondering how that is achieved in B4A
 
Upvote 0

aeric

Expert
Licensed User
Longtime User
To better help you. it is better you post a sample data showing the structure or format.
Put is overwriting the value if the key matched. If your code doesn't behave as this then there must be something wrong with your code.
 
Upvote 0

emexes

Expert
Licensed User
how to access a datum three levels down in one line of code. In VB it was: myArray(2,4,3)

If they are lists of lists of lists, then one way of doing it would be via a helper function (which might also make porting from your VB code easier too):

B4X:
Sub myArray(A As Int, B As Int, C As Int) As Object
    Return AP.Get(A).As(List).Get(B).As(List).Get(C)
End Sub

Dim Temp As String = myArray(2, 4, 3).As(String)

or if you know that the final result is always a String, then:

B4X:
Sub myArray(A As Int, B As Int, C As Int) As String
    Return AP.Get(A).As(List).Get(B).As(List).Get(C)    'don't need .As(String) since it will automatically be cast to the function's return type ie String
End Sub

Dim Temp As String = myArray(2, 4, 3)

Or you could do it inline, eg:

B4X:
Log( Return AP.Get(2).As(List).Get(4).As(List).Get(3).As(String).ToUpperCase )

where I've used .ToUpperCase as an excuse to demonstrate casting the unknown object type to String with .As(String)

List.Get (and Map.Get) return a generic (unknown type) object, and if you want to then do something with that object, then you need to use .As(type) to let B4X know what the object is so that it knows what properties and methods are applicable.

chose not to MAP it as map stores as strings

Maps and Lists store Objects, which can be Strings, but can also be anything else, including nested Maps and Lists.
 
Last edited:
Upvote 0

67biscuits

Member
To better help you. it is better you post a sample data showing the structure or format.
Put is overwriting the value if the key matched. If your code doesn't behave as this then there must be something wrong with your code.
You have said the .Put overwrites. I shall re-examine the code to make sure I am not corrupting the data. The keys are generated automatically when I hit the Save button to save a record. If the record was selected from an existing file, the key is extracted at that point and so does not need to be generated.
 
Upvote 0

emexes

Expert
Licensed User
journal entries, hours entries, financial entries

Ah, I was thinking journal as in scientific magazine or collection of scientific papers.

And then: journal entry as in a note made into a diary history.

But journal ledger, as in a list of transactions not recorded in another financial ledger, works too.
 
Upvote 0

67biscuits

Member
If they are lists of lists of lists, then one way of doing it would be via a helper function (which might also make porting from your VB code easier too):

B4X:
Sub myArray(A As Int, B As Int, C As Int) As Object
    Return AP.Get(A).As(List).Get(B).As(List).Get(C)
End Sub

Dim Temp As String = myArray(2, 4, 3).As(String)

Or you could do it inline, eg:

B4X:
Log( Return AP.Get(2).As(List).Get(4).As(List).Get(3).As(String).ToUpperCase )

where I've used .ToUpperCase as an excuse to demonstrate casting the unknown Object to a string with .As(String)



Maps and Lists store Objects, which can be Strings, but can also be anything else, including nested Maps and Lists.
I apologize, I am not porting from VB, I was referring to the 90's when I was programming front end UIs for databanks. Multi dimension arrays are confusing and can be difficult to grasp visually. When I mention mArray(2,4,3) I don't mean a list containing a 2,a 4 & a 3. I mean a mutli-dimension array where that statement reads the third datum in the 2 array of the first array. And therein lies my conundrum. How do I do that in B4A

For Aeric, I could post some code...
sample:
' this is dummed down version. Please DO NOT get hung up on _
    the syntax of how the data is getting into the lists
project_id_tag = "x9-ert-2025"

dim AllProjects as list
dim LiveProject as list
dim journal, hours, mtrls as list

'user would write in this data, but for the sample I am demonstrating the data structure it in
journal.Add ["04/07/2025", "08:00","Delivered material to job site"]
  hours.Add ["04/07/2025","08:00","09:30",1.5,65,tax=True]
  mtrls.Add ["04/07/2025","06:30","2x4s",36,5.99]
  mtrls.Add ["04/07/2025", "11:15","3-1/2 nails",2,26.99]
  hours.Add ["04/07/2025", "11:45", "12:15", .5, 65, tax=True]

LiveProject.add(journal)
LiveProject.add(hours)
LivePProject.add(mtrls)

AllProjects.Put(project_id_tag)

'please tell me what time the nails were purchased in one line of code
 
Upvote 0

67biscuits

Member
Ah, I was thinking journal as in scientific magazine or collection of scientific papers.

And then: journal entry as in a note made into a diary history.

But journal ledger, as in a list of transactions not recorded in another financial ledger, works too.
yes. not the best choice of words on my part. diary is probably a better term. In college we were taught to 'journal' the day, so it has stuck in my head. I have financial memos in the finances, not ledgers. Simple incoming and outgoing funds. Payments and refunds. Materials finance is handled elsewhere
 
Upvote 0

emexes

Expert
Licensed User
Example approximating your list-of-lists-of-lists (I think):

B4X:
Dim AP As List
AP.Initialize

Dim FirstList As List
FirstList.Initialize
AP.Add(FirstList)

Dim JournalLedger As List
JournalLedger.Initialize
AP.Add(JournalLedger)

Dim SampleJournalEntries() As String = Array As String( _
    "Andy",    "11/01/2025", 123.01, _
    "Bobby",   "19/02/2025", 456.02, _
    "Charlie", "08/03/2025", 789.03, _
    "Danny",   "25/04/2025", 135.04, _
    "Ernie",   "17/05/2025", 246.05, _
    "Freddy",  "14/06/2025", 357.06 _
)

For I = 0 To SampleJournalEntries.Length - 1 Step 3
    Dim JournalEntry As List
    JournalEntry.Initialize
    
    JournalEntry.Add(SampleJournalEntries(I + 0))    'name
    JournalEntry.Add(SampleJournalEntries(I + 1))    'date
    JournalEntry.Add(SampleJournalEntries(I + 2))    'value
    
    JournalLedger.Add(JournalEntry)
    Next

Log("*** list of lists of lists ***")
Log(AP)

Log("*** journal entry lists ***")
For I = 0 To 5
    Log(I & TAB & AP.Get(1).As(List).Get(I))
Next

Log("*** inline ***")

For I = 0 To 5
    Log(                                                  _
        I                                         & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(0) & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(1) & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(2)         _
    )
Next

Log("*** step-by-step ***")

Dim JournalLedger As List = AP.Get(1)
For I = 0 To JournalLedger.Size - 1
    Dim JournalEntry As List = JournalLedger.Get(I)
    Dim JEName  As String = JournalEntry.Get(0)
    Dim JEDate  As String = JournalEntry.Get(1)
    Dim JEValue As String = JournalEntry.Get(2)

    Log(I & TAB & JEName & TAB & JEDate & TAB & JEValue)
Next

Log output:
Waiting for debugger to connect...
Program started.
*** list of lists of lists ***
(ArrayList) [[], [[Andy, 11/01/2025, 123.01], [Bobby, 19/02/2025, 456.02], [Charlie, 08/03/2025, 789.03], [Danny, 25/04/2025, 135.04], [Ernie, 17/05/2025, 246.05], [Freddy, 14/06/2025, 357.06]]]
*** journal entry lists ***
0    [Andy, 11/01/2025, 123.01]
1    [Bobby, 19/02/2025, 456.02]
2    [Charlie, 08/03/2025, 789.03]
3    [Danny, 25/04/2025, 135.04]
4    [Ernie, 17/05/2025, 246.05]
5    [Freddy, 14/06/2025, 357.06]
*** inline ***
0    Andy    11/01/2025    123.01
1    Bobby    19/02/2025    456.02
2    Charlie    08/03/2025    789.03
3    Danny    25/04/2025    135.04
4    Ernie    17/05/2025    246.05
5    Freddy    14/06/2025    357.06
*** step-by-step ***
0    Andy    11/01/2025    123.01
1    Bobby    19/02/2025    456.02
2    Charlie    08/03/2025    789.03
3    Danny    25/04/2025    135.04
4    Ernie    17/05/2025    246.05
5    Freddy    14/06/2025    357.06
 
Upvote 0

emexes

Expert
Licensed User
Lol wonder how far that sequence could go:

Gerry, Harry, Iggy (Pop), Jerry, Kenny, Larry, Maurie, Nicky, Ollie, Percy, Quincy, Ricky, Sammy, Tommy, Uri (Geller), Vinny, Wally, Xi, Yogi (Berra), Zachary

I only cheated once. And even there I think I could get away with a "not guilty" verdict if I had to argue it in court.
 
Last edited:
Upvote 0

67biscuits

Member
Lol wonder how far that sequence could go:

Gerry, Harry, Iggy (Pop), Jerry, Kenny, Larry, Maurie, Nicky, Ollie, Percy, Quincy, Ricky, Sammy, Tommy, Uri (Geller), Vinny, Wally, Xi, Yogi (Berra), Zachary

I only cheated once. And even there I think I could get away with a "not guilty" verdict if I had to argue it in court.
cheated with gerry and jerry? George and jeremy? Gary and Jack. Gerard and James.
 
Upvote 0

67biscuits

Member
Example approximating your list-of-lists-of-lists (I think):

B4X:
Dim AP As List
AP.Initialize

Dim FirstList As List
FirstList.Initialize
AP.Add(FirstList)

Dim JournalLedger As List
JournalLedger.Initialize
AP.Add(JournalLedger)

Dim SampleJournalEntries() As String = Array As String( _
    "Andy",    "11/01/2025", 123.01, _
    "Bobby",   "19/02/2025", 456.02, _
    "Charlie", "08/03/2025", 789.03, _
    "Danny",   "25/04/2025", 135.04, _
    "Ernie",   "17/05/2025", 246.05, _
    "Freddy",  "14/06/2025", 357.06 _
)

For I = 0 To SampleJournalEntries.Length - 1 Step 3
    Dim JournalEntry As List
    JournalEntry.Initialize
  
    JournalEntry.Add(SampleJournalEntries(I + 0))    'name
    JournalEntry.Add(SampleJournalEntries(I + 1))    'date
    JournalEntry.Add(SampleJournalEntries(I + 2))    'value
  
    JournalLedger.Add(JournalEntry)
    Next

Log("*** list of lists of lists ***")
Log(AP)

Log("*** journal entry lists ***")
For I = 0 To 5
    Log(I & TAB & AP.Get(1).As(List).Get(I))
Next

Log("*** inline ***")

For I = 0 To 5
    Log(                                                  _
        I                                         & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(0) & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(1) & TAB & _
        AP.Get(1).As(List).Get(I).As(List).Get(2)         _
    )
Next

Log("*** step-by-step ***")

Dim JournalLedger As List = AP.Get(1)
For I = 0 To JournalLedger.Size - 1
    Dim JournalEntry As List = JournalLedger.Get(I)
    Dim JEName  As String = JournalEntry.Get(0)
    Dim JEDate  As String = JournalEntry.Get(1)
    Dim JEValue As String = JournalEntry.Get(2)

    Log(I & TAB & JEName & TAB & JEDate & TAB & JEValue)
Next

Log output:
Waiting for debugger to connect...
Program started.
*** list of lists of lists ***
(ArrayList) [[], [[Andy, 11/01/2025, 123.01], [Bobby, 19/02/2025, 456.02], [Charlie, 08/03/2025, 789.03], [Danny, 25/04/2025, 135.04], [Ernie, 17/05/2025, 246.05], [Freddy, 14/06/2025, 357.06]]]
*** journal entry lists ***
0    [Andy, 11/01/2025, 123.01]
1    [Bobby, 19/02/2025, 456.02]
2    [Charlie, 08/03/2025, 789.03]
3    [Danny, 25/04/2025, 135.04]
4    [Ernie, 17/05/2025, 246.05]
5    [Freddy, 14/06/2025, 357.06]
*** inline ***
0    Andy    11/01/2025    123.01
1    Bobby    19/02/2025    456.02
2    Charlie    08/03/2025    789.03
3    Danny    25/04/2025    135.04
4    Ernie    17/05/2025    246.05
5    Freddy    14/06/2025    357.06
*** step-by-step ***
0    Andy    11/01/2025    123.01
1    Bobby    19/02/2025    456.02
2    Charlie    08/03/2025    789.03
3    Danny    25/04/2025    135.04
4    Ernie    17/05/2025    246.05
5    Freddy    14/06/2025    357.06
from your samples, I have been using the step-by-step version. Which has been working. It seems inefficient, dragging in more variables, despite short lived ones.

I am looking at the in line section of your example to unpack information from that. the [ AP.Get(1).As(List).Get(I).As(List).Get(2) ] seems more .. efficient, tidy, to the point. The list of journals is displayed in a clvList, displaying the dates. The user would select the dates to view the details of the journal. A msgbox pops up and says something to the effect;
"On Monday April 7: 10:45 - Lumber was milled to usable stock and stacked in battle fomation for the carpenters. 12:20 - Brick layers went for an early lunch and got drunk. The electricians left as it was too dark to work. 13:45 - Home owner stopped by at 1:30 with a deposit cheque. 17:00 - site locked down for the night"
(each time entry is an edit to the journal entry, as opposed to have multiple entries per day.)
in the Journal case, the only data that are extracted; the date and the journal entry.
does this work?:
LP.Get(1).As(List).Get(0).As(List).Get(2)  '0 is the date in the log, 2 is the text from the journal entry
 
Upvote 0
Top