Page 1 of 2

Delete single element of an array

Posted: Sun Dec 18, 2011 11:52 am
by drahneir
Is it possible to delete a single element of an array, as is in C++ ?

Re: Delete single element of an array

Posted: Sun Dec 18, 2011 12:38 pm
by gnasen
you can use a macro for this, for example:

Code: Select all

Macro deleteArrayElement(ar, el)
  
  For a=el To ArraySize(ar())-1
    ar(a) = ar(a+1)
  Next  
  
  Redim ar(ArraySize(ar())-1)
  
EndMacro
Macro debugArray(ar,text)
  
  Debug text
  For a=0 To ArraySize(ar())
    Debug ar(a)
  Next
  
EndMacro

Dim test.i(5)

For a=0 To 5
  test(a) = a
Next

debugArray(test,"START")

deleteArrayElement(test, 2)
debugArray(test,"DELETE 2")

deleteArrayElement(test, 0)
debugArray(test,"DELETE 0")

CallDebugger

Re: Delete single element of an array

Posted: Sun Dec 18, 2011 1:55 pm
by drahneir
Thank you gnasen, this works.

Re: Delete single element of an array

Posted: Sun Dec 18, 2011 2:06 pm
by wilbert
Alternative macro

Code: Select all

Macro deleteArrayElement(ar, el)
  
  MoveMemory(@ar(el)+@ar(1)-@ar(0), @ar(el), @ar(ArraySize(ar())) - @ar(el))
  ReDim ar(ArraySize(ar())-1)
  
EndMacro

Re: Delete single element of an array

Posted: Sun Dec 18, 2011 4:31 pm
by PMV
This will crash, if the Array has only 1 element, you should
use SizeOf(Structure) to get the size of one element. :)

Code: Select all

Macro deleteArrayElement(ar, el, st)
  
  MoveMemory(@ar(el)+SizeOf(st), @ar(el), @ar(ArraySize(ar())) - @ar(el))
  ReDim ar(ArraySize(ar())-1)
  
EndMacro

Re: Delete single element of an array

Posted: Sun Dec 18, 2011 9:53 pm
by skywalk
Include Strings Too :wink:

Code: Select all

Macro arDelNthElement(ar, el, struc=ABC, Type=$)
  ; Defaults = String operation
  ; For non-String, set struc = Byte,Long,Double,etc., Type = L
  If SizeOf(struc) <> SizeOf(ABC)
    MoveMemory(@ar(el) + SizeOf(struc), @ar(el), @ar(ArraySize(ar())) - @ar(el))
  Else  ; String
    ; netmaestro: www.purebasic.fr/english/viewtopic.php?p=160630#p160630
    ar(el) = #NUL#Type   ; Free memory of deleted element
    MoveMemory(ar() + 4 * el + 4, ar() + 4 * el, PeekL(ar() - 8) * 4 - 4 * el)
  EndIf
  ReDim ar(ArraySize(ar())-1)
EndMacro

Re: Delete single element of an array

Posted: Mon Dec 19, 2011 6:19 am
by Tenaja
For a single element, why not just move everything up into its place and skip the ReDim? If you may do it a lot, then save the ReDim for a batch job.

Re: Delete single element of an array

Posted: Mon Dec 19, 2011 9:23 pm
by RichAlgeni
Just wondering for my own benefit..., would it be faster to use a Map for this, then FindMapElement and DeleteMapElement?

I'm not critiquing anyone's style, just thinking about how I might do it.

Re: Delete single element of an array

Posted: Wed Dec 21, 2011 12:01 pm
by Michael Vogel
Don't have PB here (on my android device), not sure if this will work also...

Code: Select all

Macro ArrayInsertString(name,element,content="")
	
	ReDim name(ArraySize(name())+1)
	MoveMemory(name()+4*element-4,name()+4*element+,PeekL(name()-8)*4-4*element)
	name(element)=content
	
EndMacro
Test...

Code: Select all

For i=1 To 10
	s(i)=RSet("",i,"x")
Next i

ArrayInsertString(s,5,"Will this work?")

For i=1 To ArraySize(s())
	Debug Str(i)+": "+s(i)+", "+Str(Len(s(i)))
Next i

PS: would be fine to have such (internal) commands (insert/delete element) for arrays with structures

Re: Delete single element of an array

Posted: Wed Dec 21, 2011 12:16 pm
by Trond
Remember, that if the order of the elements doesn't matter, you can do it this way:

Code: Select all

Array(ElementToDelete) = Array(ArraySize(Array))
ReDim Array(ArraySize()-1)

Re: Delete single element of an array

Posted: Wed Dec 21, 2011 5:19 pm
by Michael Vogel
The ArrayInsertString macro did not work, here's a quick and dirty procedure solution for that now. Hopefully the memory pointer of arrays can be manipulated like that with no side effects. It would be interesting for me, if structured arrays are kept in memory in a similar way -- this could speed up inserting/deleting elements a lot here...

Code: Select all

Procedure ArrayInsertString(name,element,content="")
	Protected n=ArraySize(name())+1
	ReDim name(n)
	name(n)=content
	n=PeekL(name()+4*n)
	MoveMemory(name()+4*element-4,name()+4*element,PeekL(name()-8)*4-4*element)
	PokeL(name()+4*element,n)
EndProcedure

Dim s.s(10)

For i=1 To 10
	s(i)=RSet("",i,"x")
Next i

ArrayInsertString(s,5,"Will this work?")

For i=1 To ArraySize(s())
	Debug Str(i)+": "+s(i)+", "+Str(Len(s(i)))
Next i

Re: Delete single element of an array

Posted: Thu Dec 22, 2011 10:09 am
by Kwai chang caine
Thanks Michael for this nice code 8)
So it not works, i have found several problems in the passing parameters

Code: Select all

Procedure ArrayInsertString(name,element,content="")
I hope i have not damaged your code :oops: , but now it works :D

Code: Select all

Procedure ArrayInsertString(Array name.s(1),element,content.s="")
   Protected n=ArraySize(name())+1
   ReDim name(n)
   name(n)=content
   n=PeekL(name()+4*n)
   MoveMemory(name()+4*element-4,name()+4*element,PeekL(name()-8)*4-4*element)
   PokeL(name()+4*element,n)
EndProcedure

Dim s.s(10)

For i=1 To 10
   s(i)=RSet("",i,"x")
Next i

ArrayInsertString(s(),5,"Will this work?")

For i=1 To ArraySize(s())
   Debug Str(i)+": "+s(i)+", "+Str(Len(s(i)))
Next i

Re: Delete single element of an array

Posted: Fri Dec 23, 2011 8:57 am
by Michael Vogel
I am curious, if Add/DeleteElement functions could be done easily with structured arrays as well. I just started to get an idea, how the structure will be organized in the memory.

Just started, I get the feeling, that the whole thing can't be done so easy...
First issue: "n" in the debug line can't be replaced by "test(i)-test(i-1)"
Second point: where in the memory are the strings located? Replacing "???" by "test(i)+4" does not work

Code: Select all

Structure type
	int.i
	text.s
EndStructure

Dim test.type(5)

For i=1 To 5
	test(i)\int=Pow(10,i)
	test(i)\text=Str(test(i)\int)
Next i

For i=1 To 5
	n=test(i)-test(i-1)
	Debug Str(i)+": @"+Str(test(i))+", "+Str(n)+" Byte >> "+Str(test(i)\int)+" = "+test(i)\text
	;Debug Str(i)+": @"+Str(test(i))+", "+Str(n)+" Byte >> "+Str(PeekL(test(i)))+" = "+PeekS(???)
Next i

For i=1 To 5
	Debug Str(i)+": "+Str(test(i)\int)+" = "+test(i)\text
Next i


Re: Delete single element of an array

Posted: Fri Dec 23, 2011 10:02 am
by wilbert
Michael Vogel wrote:Just started, I get the feeling, that the whole thing can't be done so easy...
Not so difficult :)

Code: Select all

Global.i _ArrSize_, _ArrElementSize_, _ArrElementAddr_

Macro ArrayRemoveElement(ar, el)
  _ArrSize_ = ArraySize(ar())
  If _ArrSize_ > 0 And el <= _ArrSize_ 
    _ArrElementSize_ = @ar(1) - @ar(0)
    _ArrElementAddr_ = @ar(el)
    MoveMemory(_ArrElementAddr_ + _ArrElementSize_, _ArrElementAddr_, @ar(_ArrSize_) - _ArrElementAddr_)
    PokeL(@ar() - 8, _ArrSize_); ReDim ar(_ArrSize_ - 1)
  EndIf
EndMacro



Structure type
  int.i
  text.s
EndStructure

Dim test.type(5)

For i=1 To 5
  test(i)\int=Pow(10,i)
  test(i)\text=Str(test(i)\int)
Next i

For i=1 To 5
  Debug Str(i)+": "+Str(test(i)\int)+" = "+test(i)\text
Next i

ArrayRemoveElement(test, 2)

For i=1 To 4
  Debug Str(i)+": "+Str(test(i)\int)+" = "+test(i)\text
Next i
The only thing I don't understand is that it crashes the second time it is called if I use ReDim.

Re: Delete single element of an array

Posted: Fri Dec 23, 2011 3:43 pm
by Trond
Second point: where in the memory are the strings located?
Strings are just stored as a pointer. The real string could be anywhere.