Page 1 of 2

Prefilling a List

Posted: Sun Dec 24, 2023 7:05 pm
by jchase1970
Is there a way to take a set of information and create the list directly with it without using the addelement command

For example,
I have a set of numbers 1,2,3,4,5,8,9,11,15,17,19,45,65,78 and so on could be a really big set
I want to have them all in a searchable list or other item like an array is fine too
Is there a way I can say list="1,2,3,4,5,8,9,11,15,17,19,45,65,78" to create the list predefined?
Over having to have all the addelement commands?

Re: Prefilling a List

Posted: Sun Dec 24, 2023 7:19 pm
by Quin
Nope. It's incredibly unfortunate, but I also highly doubt it will ever be added due to the attitudes of many users (and maybe the PB devs themselves) about syntax sugar.

Re: Prefilling a List

Posted: Sun Dec 24, 2023 7:19 pm
by Paul
Maybe something like this?

Code: Select all

set.s="[1,2,3,4,5,8,9,11,15,17,19,45,65,78]"

NewList myset()
ParseJSON(0, set)
ExtractJSONList(JSONValue(0), myset())

ForEach myset()
  Debug myset()
Next

Re: Prefilling a List

Posted: Sun Dec 24, 2023 7:28 pm
by skywalk
I agree, this has been requested many times.
But why add a syntax case for an extremely simple case?
I rarely have lists or maps of single elements.

I have an init() function for most of my apps.
It is no big deal with cut and paste. :idea:

Re: Prefilling a List

Posted: Sun Dec 24, 2023 7:36 pm
by jchase1970
skywalk, how do you add hundreds of items to a list, is it really a long section of code filled with,

AddElement(MyList())
MyList() = x

This is so inefficient, ugly and bloating code, even with copy and pasting.
I just can't believe there is not a easy way to create a list of data.

Re: Prefilling a List

Posted: Sun Dec 24, 2023 7:49 pm
by skywalk
You use a loop construct for the list loads. :idea:
The cut and paste I'm referring is where you enter your fixed values?
They can be in a csv or a datasection or even a SQLite database.

Code: Select all

ResetList(llTPS())
nPts = GetYourData(d())
If nPts > 1
  For i = 0 To nPts - 1
    AddElement(llTPS())
    llTPS() = d(i)
  Next i
EndIf

Re: Prefilling a List

Posted: Sun Dec 24, 2023 8:00 pm
by jchase1970
skywalk,
The solution I am using is storing the info in Data statements and doing I think basically what you are saying
For l=1 To 40
Read a
AddElement(set())
set() = a
Next

Re: Prefilling a List

Posted: Sun Dec 24, 2023 8:02 pm
by skywalk
Yes, that is one way.
But, your data is hardcoded to your exe.
If your data changes or grows, better to use external files or databases.

Re: Prefilling a List

Posted: Sun Dec 24, 2023 10:09 pm
by Oso
I often tend to favour the use of maps rather than lists, partly because they are so much easier to populate, with a single statement, but I also find them easier to manage. I've always found lists to be a bit arcane. But it depends on performance considerations and the below may not suit everyone — it works for certain tasks, but not if sorting sequence is a factor.

Code: Select all

EnableExplicit
NewMap List()

List("10")
List("12")
List("18")
List("25")

ForEach List()
  Debug MapKey(List())
Next

Re: Prefilling a List

Posted: Mon Dec 25, 2023 12:44 am
by DeanH
I do this old-school by brute force with a set of procedures.
I use lists when a key is not required, and maps when keys are useful.
Lists can be sorted as well.

Code: Select all

;This procedure adds an integer value to a list, optionally at a specified position
Procedure ListAddn(List tempb.i(), value.i , position=-1)
	Protected top
	top=ListSize(tempb())
	If pos>top Or position=-1
		AddElement(tempb())
		tempb()=value
		ProcedureReturn
	EndIf
	SelectElement(tempb(), position)
	InsertElement(tempb())
	tempb()=value
EndProcedure

;Add a string value to a list only if the value is not in the list
Procedure.i ListAddS(List temp$(), value$, checkcase=#True)
	Protected added, lookfor$, found, a$
	If value$
		;check to see if value$ is already in list temp$()
		lookfor$=value$
		If checkcase
			lookfor$=LCase(lookfor$)
		EndIf
		ForEach temp$()
			a$=temp$()
			If checkcase
				a$=LCase(a$)
			EndIf
			If lookfor$=a$
				found=#True
				Break
			EndIf
		Next
		If found=#False
			AddElement(temp$())
			temp$()=value$
			added=#True
		EndIf
		ResetList(temp$())
	EndIf
	ProcedureReturn added
EndProcedure

Procedure.i MakeList(List mylist.i(),listtoadd$)
	Protected n, i, a$
	n=CountString(listtoadd$, ",")+1
	For i=1 To n
		a$=StringField(listtoadd$, i, ",")
		ListAddn(mylist(), Val(a$))
	Next
	ProcedureReturn n
EndProcedure


NewList TestList.i()
alist$="2,8,11,4,78,5,3,9,1,19,14,19,65,45"
MakeList(TestList(),alist$)
SortList(TestList(),#PB_Sort_Ascending)
ForEach TestList()
	Debug TestList()
Next

End

I was not able to get the JSON example to work within a procedure (below). Error report is "A JSON value of type array is expected".

Procedure MakeList(List mylist(), set$)
CreateJSON(0)
ParseJSON(0, set$)
ExtractJSONList(JSONValue(0), mylist()) ;error on this line
FreeJSON(0)
EndProcedure

Re: Prefilling a List

Posted: Mon Dec 25, 2023 1:34 am
by Olli
Is it ok ?

(this syntax :
myMacro(arg1 arg2 arg3 ...)
)

Code: Select all

Macro quote()
"
EndMacro

Macro listSplit(arg)
 tmp$ = quote()arg#quote()
 For privateI = 1 To CountString(tmp$, " ") + 1
  AddElement(*currentList\x() )
  *currentList\x() = Val(StringField(tmp$, privateI, " ") )
 Next
EndMacro

Structure myList
 List x.i()
EndStructure

Global *currentList.myList

Procedure myListCreate()
 Protected *this.myList = AllocateMemory(SizeOf(myList) )
 InitializeStructure(*this, myList)
 *currentList = *this
 ProcedureReturn *this
EndProcedure

Define *x.myList = myListCreate()

listSplit(1 2 4 8 16 32)

ForEach(*x\x() )
 Debug *x\x()
Next

Re: Prefilling a List

Posted: Mon Dec 25, 2023 1:56 am
by AZJIO
You are using unnecessary garbage in your code. If it seems to you that it is easier to write this way, but this does not mean that it is good for the program.

Code: Select all

EnableExplicit
; https://www.purebasic.fr/english/viewtopic.php?f=12&t=65159&p=486382&hilit=SplitL#p486382
Procedure SplitL(String.s, List StringList.s(), Separator.s = " ")
	
	Protected S.String, *S.Integer = @S
	Protected.i p, slen
	slen = Len(Separator)
	ClearList(StringList())
	
	*S\i = @String
	Repeat
		AddElement(StringList())
		p = FindString(S\s, Separator)
		StringList() = PeekS(*S\i, p - 1)
		*S\i + (p + slen - 1) << #PB_Compiler_Unicode
	Until p = 0
	*S\i = 0
	
EndProcedure

Global NewList NumStr.s()
Global NewList Num.i()
Global s$ = "1,2,3,4,5,8,9,11,15,17. ,19,45,65,78"
SplitL(s$, NumStr(), ",")
ForEach NumStr()
	If AddElement(Num())
		Num() = Val(NumStr())
	EndIf
Next
FreeList(NumStr())

ForEach Num()
	Debug Num()
Next

Re: Prefilling a List

Posted: Thu Dec 28, 2023 4:21 pm
by ebs
DeanH wrote: Mon Dec 25, 2023 12:44 am I was not able to get the JSON example to work within a procedure (below). Error report is "A JSON value of type array is expected".

Procedure MakeList(List mylist(), set$)
CreateJSON(0)
ParseJSON(0, set$)
ExtractJSONList(JSONValue(0), mylist()) ;error on this line
FreeJSON(0)
EndProcedure
This works fine:

Code: Select all

set.s = "[1,2,3,4,5,8,9,11,15,17,19,45,65,78]"

NewList myset()

Procedure MakeList(List mylist(), set.s)
  CreateJSON(0)
  ParseJSON(0, set)
  ExtractJSONList(JSONValue(0), mylist())
  FreeJSON(0)
EndProcedure

MakeList(myset(), set)

ForEach myset()
  Debug myset()
Next

Re: Prefilling a List

Posted: Thu Dec 28, 2023 4:52 pm
by Marc56us
AddElement(MyList())
MyList() = x
This is so inefficient, ugly and bloating code, even with copy and pasting.
But a compiler doesn't think and work like a human: it's often much faster for it to repeat simple assignment instructions than to perform calculations.

How many instructions in ASM or C to do this like that rather than other solutions (i.e Json) ?
(I don't know, but I think only two instructions per variable ?)

Code: Select all

NewList myset()

AddElement(myset()) : myset() = 1
AddElement(myset()) : myset() = 2
AddElement(myset()) : myset() = 3
AddElement(myset()) : myset() = 4
AddElement(myset()) : myset() = 5 
AddElement(myset()) : myset() = 8
AddElement(myset()) : myset() = 9
AddElement(myset()) : myset() = 11
AddElement(myset()) : myset() = 15
AddElement(myset()) : myset() = 17
AddElement(myset()) : myset() = 19
AddElement(myset()) : myset() = 45
AddElement(myset()) : myset() = 65
AddElement(myset()) : myset() = 78
For those sort of code, I do one line
AddElement(myset()) : myset() =
and press CTRL + D x time, then edit end of lines
Fast
Easy to read

:idea: And you can use Macros if you don't want to clutter up your code (in which case the code will be written at the last minute).

And If there were hundreds of values, then I'd use "Read Data", simply because it's readable too.
:arrow: Always keep in mind that you may have to modify a code several months or years later.

:wink:

Re: Prefilling a List

Posted: Thu Dec 28, 2023 5:09 pm
by AZJIO
Marc56us wrote: Thu Dec 28, 2023 4:52 pm and press CTRL + D
replace the comma with #CRLF$ + AddElement(myset()) : myset() =
If the JSON engine is built into the program initially, then you can use it, but for the sake of a small list, I would not embed a third-party module.