delete map element

Just starting out? Need help? Post your questions and find answers here.
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

delete map element

Post 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
Last edited by mestnyi on Sun Dec 24, 2023 5:03 pm, edited 2 times in total.
Oso
Enthusiast
Enthusiast
Posts: 595
Joined: Wed Jul 20, 2022 10:09 am

Re: delete map element

Post 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
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: delete map element

Post 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

Re: delete map element

Post 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
      
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: delete map element

Post 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

Re: delete map element

Post 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.
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

Re: delete map element

Post 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())
User avatar
STARGÅTE
Addict
Addict
Posts: 2260
Joined: Thu Jan 10, 2008 1:30 pm
Location: Germany, Glienicke
Contact:

Re: delete map element

Post 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.
PB 6.01 ― Win 10, 21H2 ― Ryzen 9 3900X, 32 GB ― NVIDIA GeForce RTX 3080 ― Vivaldi 6.0 ― www.unionbytes.de
Lizard - Script language for symbolic calculations and moreTypeface - Sprite-based font include/module
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

Re: delete map element

Post 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
    
AZJIO
Addict
Addict
Posts: 2227
Joined: Sun May 14, 2017 1:48 am

Re: delete map element

Post by AZJIO »

Code: Select all

ForEach root( )
	Debug root( )\class
	FreeGadget( root( )\canvas\gadget )
	CloseWindow( root( )\canvas\window )
Next
ClearMap(root())
mestnyi
Addict
Addict
Posts: 1103
Joined: Mon Nov 25, 2013 6:41 am

Re: delete map element

Post 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
Post Reply