Page 1 of 1
delete map element
Posted: Fri Dec 01, 2023 5:45 pm
by mestnyi
how is this supposed to work?
Code: Select all
Global NewMap Country.s()
Country("US") = "United States"
Country("FR") = "France"
Country("GE") = "Germany"
If DeleteMapElement( Country() )
Debug Country()
EndIf
If DeleteMapElement( Country() )
Debug Country()
EndIf
If DeleteMapElement( Country() )
Debug Country()
EndIf
is not it?
Code: Select all
Procedure __DeleteMapElement( Map MapList.s( ), key.s = "" )
If key
DeleteMapElement(MapList(), key)
Else
DeleteMapElement(MapList())
EndIf
ResetMap(MapList())
NextMapElement(MapList())
If MapSize(MapList())
ProcedureReturn @MapList()
EndIf
EndProcedure
Global NewMap Country.s()
Country("US") = "United States"
Country("FR") = "France"
Country("GE") = "Germany"
If __DeleteMapElement( Country() )
Debug Country()
EndIf
If __DeleteMapElement( Country() )
Debug Country()
EndIf
If __DeleteMapElement( Country() )
Debug Country()
EndIf
that works too that is, the compiler does not give an error
Code: Select all
Global NewMap Country.s()
Country("US") = "United States"
Country("FR") = "France"
Country("GE") = "Germany"
If DeleteMapElement( Country(), MapKey(Country()) )
Debug Country()
EndIf
If DeleteMapElement( Country(), MapKey(Country()) )
Debug Country()
EndIf
If DeleteMapElement( Country(), MapKey(Country()) )
Debug Country()
EndIf
Re: delete map element
Posted: Fri Dec 01, 2023 6:06 pm
by Oso
Hello mestnyi, as explained in the help documentation for DeleteMapElement(), the element after deletion is arbitrary, so you need to either specify it or do something to select a new current element. Your first example code isn't doing that — but is instead attempting to delete a non-existent element. You can specify the element to delete, using the optional second parameter for DeleteMapElement().
"After this call, the new current element is the previous element (the one before the deleted element), which is an arbitrary element, as a map isn't sorted." —
https://www.purebasic.com/documentation ... ement.html
Re: delete map element
Posted: Fri Dec 01, 2023 7:38 pm
by STARGÅTE
A map is not a linked list.
What is your aim in the first (or second as well) code, to delete three "random" map elements and debugging each time the arbitrary element after the deletion? Because, even if you use ResetMap() and NextMapElement(), the new selected element is again arbitrary and not (as you might think) "US" as you created it first.
Please look at this example:
Code: Select all
Global NewMap Country.s()
Country("US") = "United States"
Country("FR") = "France"
Country("GE") = "Germany"
ResetMap(Country())
NextMapElement(Country())
Debug "First Element is: " + MapKey(Country())
; Other elements
ClearMap(Country())
Country("US") = "United States"
Country("FR") = "France"
Country("IT") = "Italy"
ResetMap(Country())
NextMapElement(Country())
Debug "First Element is now: " + MapKey(Country())
Edit: The documentation of
ResetMap() and
NextMapElement() is misleading as it suggests that the map elements are in the order in which they were created.
I will add the request to change the documentation in this point.
Re: delete map element
Posted: Fri Dec 01, 2023 9:50 pm
by mestnyi
I know that they are not sorted, for me it does not matter, it is important for me that after deleting any of the existing ones is relevant.
can you download my code and run the example in the path "widget\example\container's\root\close.pb"?
https://github.com/mestnyi33/widget
I encountered this problem in these procedures.
Code: Select all
Procedure.i Free( *this._S_WIDGET )
If *this
If Not Send( *this, #__event_free )
If *this = Root( )
DeleteMapElement( Root( ), MapKey( Root( ) ) )
; DeleteMapElement( Root( ) )
; ResetMap( Root( ) )
; NextMapElement( Root( ) )
EndIf
Debug " free - "+*this\class
; еще не проверял
If ListSize( *this\events( ) )
; Debug "free-events " + *this\events( )
ClearList( *this\events( ) )
EndIf
If PopupWindow( ) = *this
PopupWindow( ) = #Null
EndIf
;\\
If Not *this\parent
*this\parent = *this
EndIf
;\\
If OpenListWidget( ) = *this
OpenList( *this\parent )
EndIf
If *this\parent\FirstWidget( ) = *this
*this\parent\FirstWidget( ) = *this\AfterWidget( )
EndIf
If *this\parent\LastWidget( ) = *this
*this\parent\LastWidget( ) = *this\BeforeWidget( )
EndIf
If *this\parent\TabBox( )
If *this\parent\TabBox( ) = *this
FreeStructure( *this\parent\TabBox( ) )
*this\parent\TabBox( ) = 0
EndIf
*this\parent\TabBox( ) = #Null
EndIf
If *this\parent\scroll
If *this\parent\scroll\v = *this
FreeStructure( *this\parent\scroll\v )
*this\parent\scroll\v = 0
EndIf
If *this\parent\scroll\h = *this
FreeStructure( *this\parent\scroll\h )
*this\parent\scroll\h = 0
EndIf
; *this\parent\scroll = #Null
EndIf
If *this\parent\type = #__type_Splitter
If *this\parent\split_1( ) = *this
FreeStructure( *this\parent\split_1( ) )
*this\parent\split_1( ) = 0
EndIf
If *this\parent\split_2( ) = *this
FreeStructure( *this\parent\split_2( ) )
*this\parent\split_2( ) = 0
EndIf
EndIf
;
If *this\parent\haschildren
LastElement(*this\_widgets( ))
Repeat
If *this\_widgets( ) = *this Or IsChild( *this\_widgets( ), *this )
If *this\_widgets( )\root\haschildren > 0
*this\_widgets( )\root\haschildren - 1
If *this\_widgets( )\parent <> *this\_widgets( )\root
*this\_widgets( )\parent\haschildren - 1
EndIf
If *this\_widgets( )\TabBox( )
If *this\_widgets( )\TabBox( ) = *this\_widgets( )
Debug " free - tab " + *this\_widgets( )\TabBox( )\class
FreeStructure( *this\_widgets( )\TabBox( ) )
*this\_widgets( )\TabBox( ) = 0
EndIf
*this\_widgets( )\TabBox( ) = #Null
EndIf
If *this\_widgets( )\scroll
If *this\_widgets( )\scroll\v
Debug " free - scroll-v " + *this\_widgets( )\scroll\v\class
FreeStructure( *this\_widgets( )\scroll\v )
*this\_widgets( )\scroll\v = 0
EndIf
If *this\_widgets( )\scroll\h
Debug " free scroll-h - " + *this\_widgets( )\scroll\h\class
FreeStructure( *this\_widgets( )\scroll\h )
*this\_widgets( )\scroll\h = 0
EndIf
; *this\_widgets( )\scroll = #Null
EndIf
If *this\_widgets( )\type = #__type_Splitter
If *this\_widgets( )\split_1( )
Debug " free - splitter - first " + *this\_widgets( )\split_1( )\class
FreeStructure( *this\_widgets( )\split_1( ) )
*this\_widgets( )\split_1( ) = 0
EndIf
If *this\_widgets( )\split_2( )
Debug " free - splitter - second " + *this\_widgets( )\split_2( )\class
FreeStructure( *this\_widgets( )\split_2( ) )
*this\_widgets( )\split_2( ) = 0
EndIf
EndIf
If *this\_widgets( )\bounds\attach
;Debug " free - attach " +*this\_widgets( )\bounds\attach\parent\class
*this\_widgets( )\bounds\attach\parent = 0
FreeStructure( *this\_widgets( )\bounds\attach )
*this\_widgets( )\bounds\attach = #Null
EndIf
*this\_widgets( )\address = 0
Debug " free - " + *this\_widgets( )\class
DeleteElement( *this\_widgets( ), 1 )
EndIf
If *this\root\haschildren = 0
Break
EndIf
ElseIf PreviousElement( *this\_widgets( )) = 0
Break
EndIf
ForEver
EndIf
If EnteredWidget( ) = *this
EnteredWidget( ) = *this\parent
EndIf
If FocusedWidget( ) = *this
FocusedWidget( ) = *this\parent
EndIf
;\\
;PostEventCanvasRepaint( *this\parent\root, #__event_free )
;ClearStructure( *this, _S_WIDGET )
ProcedureReturn 1
EndIf
EndIf
EndProcedure
Procedure WaitClose( *this._S_WIDGET = #PB_Any, waitTime.l = 0 )
Protected result
Protected *ew._S_WIDGET
Protected *window._S_WIDGET
If Root( )
If *this = #PB_Any
*window = Root( )\window
Else
*window = *this\window
EndIf
;
PushMapPosition(Root( ))
ForEach Root( )
PostEventCanvasRepaint( Root( ), #__event_create )
Next
PopMapPosition(Root( ))
Repeat
Select WaitWindowEvent( waittime )
Case #PB_Event_CloseWindow
Protected free_state
Protected canvasID = PB(GadgetID)( PB(GetWindowData)( PB(EventWindow)( ) ) )
ChangeCurrentRoot( canvasID )
Debug "close.... " + Root( )\canvas\window +" "+ PB(EventWindow)( )
;\\
If Send( Root( ), #__event_Close )
If Not PB(IsWindow)( PB(EventWindow)( ) )
free_state = 1
EndIf
Else
If Root( )\canvas\window <> PB(EventWindow)( )
Debug "change event window - " + Root( )\canvas\window +" to window - "+ PB(EventWindow)( )
ChangeCurrentRoot( canvasID )
EndIf
free_state = 1
EndIf
If free_state = 1
ForEach Root( )
If Root( )\canvas\window = PB(EventWindow)( )
Debug " freeee "+Root( )\class
If Free( Root( ) )
free_state = - 1
EndIf
EndIf
Next
If MapSize( Root( ) )
If MapKey( Root( ) ) = ""
ResetMap( Root( ) )
NextMapElement( Root( ) )
EndIf
EndIf
If free_state = - 1
If PB(IsWindow)( PB(EventWindow)( ) )
PB(CloseWindow)( PB(EventWindow)( ) )
EndIf
free_state = 0
EndIf
EndIf
; Static count
; count = 0
; ForEach Root( )
; If PB(EventWindow)( ) = Root( )\canvas\window
; Free( Root( ) )
; count + 1
; EndIf
; Next
;
; ;\\
; If count > 1
; ResetMap( Root( ) )
; NextMapElement( Root( ) )
; EndIf
;\\
If Not MapSize( Root( ) )
Debug "---------break1--------"
Break
EndIf
Case #PB_Event_RestoreWindow
Debug "restore.... "
Send( Root( ), #__event_Restore )
Case #PB_Event_MaximizeWindow
Debug "maximize.... "
If Send( Root( ), #__event_Maximize )
SetWindowState( PB(EventWindow)( ), #PB_Window_Normal )
EndIf
Case #PB_Event_MinimizeWindow
Debug "minimize.... "
If Send( Root( ), #__event_Minimize )
SetWindowState( PB(EventWindow)( ), #PB_Window_Normal )
EndIf
EndSelect
ForEver
;\\
If IsWindow( PB(EventWindow)( ))
Debug " - end cicle - yes event window"
PB(CloseWindow)( PB(EventWindow)( ))
Else
Debug " - end cicle - no event window"
EndIf
End
EndIf
EndProcedure
Re: delete map element
Posted: Fri Dec 01, 2023 10:59 pm
by STARGÅTE
mestnyi wrote: Fri Dec 01, 2023 9:50 pm
I know that they are not sorted, for me it does not matter, it is important for me that after deleting any of the existing ones is relevant.
But why? What did you do with such arbitrary element, which is eventually selected after a deletion?
If I delete e.g. key "A", why you need after this deletion the key "B" or "C" or what ever?
And what's even worse, if you delete the last element of your map, you have to check with MapSize() if there is a current element, anyway.
I also don't understand your third code with DeleteMapElement( Country(), MapKey(Country()) )
What do you mean with "that works too"?
This code just deletes the element with the key "GE", because Country("GE") is the last creation and therefore the current element. After you call DeleteMapElement() with a specified key, DeleteMapElement() returns 0. Now Country() has no current element, and MapKey(Country()) is always an empty string "", so the next call of DeleteMapElement( Country(), MapKey(Country()) ) tries to delete an element with key "", which doesn't exists, so no more deletion happens.
This is how it "should work"?
I'm sorry when I miss something here.
Re: delete map element
Posted: Sat Dec 02, 2023 4:53 am
by mestnyi
But why? What did you do with such a random element that ends up getting selected after being deleted?
Nothing. For me it is more important that the compiler does not stop working. When I need the current one, I just select it like this
Code: Select all
Macro ChangeCurrentRoot(_canvas_gadget_address_ )
FindMapElement( widget::Root( ), Str( _canvas_gadget_address_ ) )
EndMacro
ChangeCurrentRoot( canvasID )
didn't you run my example?
And to make matters worse, if you delete the last element of your map, you will still have to check with MapSize() whether the current element exists.
so after deletion there should remain some current one that is in the list.
I also don't understand your third code with DeleteMapElement( Country(), MapKey(Country()) ).
What do you mean by "this works too"?
if you would run my code with and without it
then you would understand what I mean.
Re: delete map element
Posted: Sat Dec 02, 2023 7:34 am
by mestnyi
Here’s another example: 1) the option does not delete everything, but 2) the option deletes everything. in a real example although I couldn't reproduce it here. why could this be?
Code: Select all
Structure Country
value.i
Country.s
EndStructure
NewMap Country.Country()
Country("GE")\Country = "Germany"
Country("IT")\Country = "Italy"
Country("FR")\Country = "France"
Country("US")\Country = "United States"
Country("GE")\value = 1
Country("IT")\value = 2
Country("FR")\value = 2
Country("US")\value = 2
value = 2
;1) option
ForEach Country()
If Country()\value = value
DeleteMapElement( Country())
EndIf
Next
;2) option
; ForEach Country()
; If Country()\value = value
; DeleteMapElement( Country(), MapKey(Country()))
; ResetMap(Country())
; EndIf
; Next
Debug MapSize(Country())
Re: delete map element
Posted: Sat Dec 02, 2023 10:51 am
by STARGÅTE
mestnyi wrote: Sat Dec 02, 2023 7:34 am
Here’s another example: 1) the option does not delete everything, but 2) the option deletes everything. in a real example although I couldn't reproduce it here. why could this be?
I can't reproduce it. Both options delete all map elements where the value was 2 and the debugger show a map size of 1 in both cases. You don' t need a ResetMap() here, because DeleteMapElement() (without specified key!) jumps back to the previous element so that ForEach works properly. But you are not allowed to specify a key in DeleteMapElement() within the ForEach loop.
The second option is even more unnecessary, as you always reset the whole iteration. This means, you check multiple times the elements in the beginning wich are not deleted, wasting a lot of time.
mestnyi wrote: Sat Dec 02, 2023 4:53 am
didn't you run my example?
I tried, but no error occurs no matter how I close the windows.
mestnyi wrote: Sat Dec 02, 2023 4:53 am
so after deletion there should remain some current one that is in the list.
How should this work, if you delete the last element and no more element is in the map?
I'm sorry, I still don't understand your argumentation.
Re: delete map element
Posted: Sun Dec 24, 2023 3:12 pm
by mestnyi
Why does it work here, but not in the real example?
https://github.com/mestnyi33/widget/blo ... itclose.pb
when a map is created with this sequence
Code: Select all
window_2_root
window_1_root
window_0_root
or
Code: Select all
window_0_root
window_2_root
window_1_root

;
Code: Select all
EnableExplicit
Structure canvas
gadget.i
window.i
EndStructure
Structure root
class.s
canvas.canvas
EndStructure
Global NewMap root.root()
;\\
OpenWindow(0, 0, 0, 300, 200, "window_0", #PB_Window_SystemMenu |
#PB_Window_SizeGadget |
#PB_Window_MinimizeGadget |
#PB_Window_MaximizeGadget )
CanvasGadget(0, 10,10,280,180)
;\\
OpenWindow(1, 200, 100, 300, 200, "window_1", #PB_Window_SystemMenu |
#PB_Window_SizeGadget |
#PB_Window_MinimizeGadget |
#PB_Window_MaximizeGadget )
CanvasGadget(1, 10,10,280,180)
;\\
OpenWindow(2, 400, 200, 300, 200, "window_2", #PB_Window_SystemMenu |
#PB_Window_SizeGadget |
#PB_Window_MinimizeGadget |
#PB_Window_MaximizeGadget )
CanvasGadget(2, 10,10,280,180)
root( Str( GadgetID(0) ) )\class = "window_0"
root( )\canvas\window = 0
root( )\canvas\gadget = 0
root( Str( GadgetID(1) ) )\class = "window_1"
root( )\canvas\window = 1
root( )\canvas\gadget = 1
root( Str( GadgetID(2) ) )\class = "window_2"
root( )\canvas\window = 2
root( )\canvas\gadget = 2
;\\
ForEach root( )
Debug root( )\class
Next
Debug ""
ForEach root( )
Debug root( )\class
FreeGadget( root( )\canvas\gadget )
CloseWindow( root( )\canvas\window )
DeleteMapElement(root( ))
Next
If Not MapSize(root( ))
Debug "0"
End
EndIf
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Re: delete map element
Posted: Mon Dec 25, 2023 2:14 am
by AZJIO
Code: Select all
ForEach root( )
Debug root( )\class
FreeGadget( root( )\canvas\gadget )
CloseWindow( root( )\canvas\window )
Next
ClearMap(root())
Re: delete map element
Posted: Mon Dec 25, 2023 4:52 am
by mestnyi
This approach is unacceptable, I think, do you know why? because "deletemapelement()" is inside "procedure free()"
If you delete it like this, it always works well.
Code: Select all
ForEach enumRoot( )
Debug enumRoot( )\class
FreeGadget( enumRoot( )\canvas\gadget )
; CloseWindow( enumRoot( )\canvas\window )
DeleteMapElement(enumRoot( ))
Next
I found a workaround: you need to call "deletemapelement()" before "closewindow()" and then call "resetmap()".
Code: Select all
Define canvas, window
ForEach enumRoot( )
Debug enumRoot( )\class
canvas = enumRoot( )\canvas\gadget
window = enumRoot( )\canvas\window
DeleteMapElement(enumRoot( ))
FreeGadget( canvas )
CloseWindow( window )
ResetMap(enumRoot( ))
Next