M_list(3f) - [M_list::INTRO] maintain simple lists (LICENSE:PD)
Synopsis
Description
Examples
Examples
Author
License
Usage:
use M_list, only : insert, replace, remove, locate use M_list, only : dictionary
The M_list(3fm) module allows for maintaining an allocatable array of intrinsic type (REAL, INTEGER, CHARACTER) as a sorted list. An example is given that creates a keyword-value dictionary using the lists.
The lists are maintained as simple allocatable arrays. Each time an entry is added or deleted the array is re-allocated. Because of the expense of reallocating the data these routines are best suited for maintaining small lists that do not change size frequently.
The advantage of this simplistic approach is that the dictionary components are simple arrays of intrinsic types which can be easily accessed with standard routines. It is easy to understand, as it works with simple arrays. For more demanding applications this would be implemented as a linked list, which there are a number of freely available examples of; several are listed on the Fortran Wiki.
subroutine locate(list,value,place,ier,errmsg) finds the index where a value is found or should be in a sorted array and flag if the value exists already subroutine insert(list,value,place) insert entry into an allocatable array at specified position subroutine replace(list,value,place) replace entry in an allocatable array at specified position subroutine remove(list,place) remove entry from an allocatable array at specified position
Sample program
program demo_M_list use M_list, only : insert, locate, replace, remove ! create a dictionary with character keywords, values, and value lengths ! using the routines for maintaining a listResultsuse M_list, only : locate, insert, replace implicit none character(len=:),allocatable :: keywords(:) character(len=:),allocatable :: values(:) integer,allocatable :: counts(:) integer :: i ! insert and replace entries call update(’b’,’value of b’) call update(’a’,’value of a’) call update(’c’,’value of c’) call update(’c’,’value of c again’) call update(’d’,’value of d’) call update(’a’,’value of a again’) ! show array write(*,’(*(a,"==>","[",a,"]",/))’)& & (trim(keywords(i)),values(i)(:counts(i)),i=1,size(keywords)) ! remove some entries call update(’a’) call update(’c’) write(*,’(*(a,"==>","[",a,"]",/))’)& & (trim(keywords(i)),values(i)(:counts(i)),i=1,size(keywords)) ! get some values write(*,*)’get b=>’,get(’b’) write(*,*)’get d=>’,get(’d’) write(*,*)’get notthere=>’,get(’notthere’) ! contains subroutine update(key,valin) character(len=*),intent(in) :: key character(len=*),intent(in),optional :: valin integer :: place integer :: ilen character(len=:),allocatable :: val if(present(valin))then val=valin ilen=len_trim(val) ! find where string is or should be call locate(keywords,key,place) ! if string was not found insert it if(place.lt.1)then call insert(keywords,key,iabs(place)) call insert(values,val,iabs(place)) call insert(counts,ilen,iabs(place)) else call replace(values,val,place) call replace(counts,ilen,place) endif else call locate(keywords,key,place) if(place.gt.0)then call remove(keywords,place) call remove(values,place) call remove(counts,place) endif endif end subroutine update function get(key) result(valout) character(len=*),intent(in) :: key character(len=:),allocatable :: valout integer :: place ! find where string is or should be call locate(keywords,key,place) if(place.lt.1)then valout=’’ else valout=values(place)(:counts(place)) endif end function get end program demo_M_list
> d==>[value of d] > c==>[value of c again] > b==>[value of b] > a==>[value of a again] > > d==>[value of d] > b==>[value of b] > > get b=>value of b > get d=>value of d > get notthere=>
A basic dictionary that uses the basic M_list functions.
Consider using generic linked-list based dictionaries when heavy usage is required, now that that is available in more recent versions of Fortran.
Note: this does not work with gfortran(1) up to at least 7.4.0 but works from at least 10.3.0 and onward.
Dictionary type definition:
type dictionary character(len=:),allocatable :: key(:) character(len=:),allocatable :: value(:) integer,allocatable :: count(:) contains procedure,public :: get => dict_get procedure,public :: set => dict_add procedure,public :: del => dict_delete procedure,public :: clr => dict_clear end type dictionary%get get value from type(dictionary) given an existing key %set set or replace value for type(dictionary) given a key %del delete an existing key from type(dictionary) %clr empty a type(dictionary) %ifdef test if name is defined
Sample program
program test_dictionary use M_list, only : dictionary implicit none type(dictionary) :: table ! ! create a character string dictionary ! call table%set(’A’,’aye’) call table%set(’B’,’bee’) call table%set(’C’,’see’) call table%set(’D’,’dee’) ! write(*,*)’A=’,table%get(’A’) write(*,*)’C=’,table%get(’C’) write(*,*)’notthere=’,table%get(’notthere’) ! call print_dict() ! ! delete dictionary entries ! call table%del(’A’) call table%del(’C’) call table%del(’z’) ! a noop as there is no key of ’z’ ! call print_dict() ! ! clear dictionary ! call table%clr() ! call print_dict() ! contains ! subroutine print_dict() integer :: i ! the dictionary is just three arrays write(*,’("DICTIONARY:")’) write(*,’(*(a,"==>","[",a,"]",/))’) & & (trim(table%key(i)), & & table%value(i)(:table%count(i)), & & i=1,size(table%key)) ! end subroutine print_dict ! end program test_dictionary
John S. Urban
Public Domain
Nemo Release 3.1 | M_list (3) | February 23, 2025 |
clr(3f) - [M_list::dictionary::OOPS] clear basic dictionary (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
type(dictionary) :: dict
call dict%clr()
clear a basic dictionary.
DICT the dictionary.
create and clear a basic dictionary
program demo_clr use M_list, only : dictionary implicit none type(dictionary) :: caps integer :: i ! create a character string dictionary call caps%set(’A’,’aye’) call caps%set(’B’,’bee’) call caps%set(’C’,’see’) call caps%set(’D’,’dee’) ! show current dictionary write(*,’("DICTIONARY BEFORE CLEARED")’) write(*,101)(trim(caps%key(i)),trim(caps%value(i)),i=1,size(caps%key)) call caps%clr() write(*,’("DICTIONARY AFTER CLEARED")’) ! show current dictionary write(*,101)(trim(caps%key(i)),trim(caps%value(i)),i=1,size(caps%key))Results101 format (1x,*(a,"=’",a,"’",:,",")) end program demo_clr
> DICTIONARY BEFORE CLEARED > D=’dee’,C=’see’,B=’bee’,A=’aye’ > DICTIONARY AFTER CLEARED
John S. Urban
Public Domain
Nemo Release 3.1 | clr (3) | February 23, 2025 |
del(3f) - [M_list::dictionary::OOPS] delete entry by key name from a basic dictionary (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
type(dictionary) :: dict
character(len=*),intent(in) :: keydict%del(key)
Delete an entry from a basic dictionary if it is present.
DICT the dictionary. KEY the key name to find and delete from the dictionary.
Delete an entry from a dictionary by key name.
program demo_del use M_list, only : dictionary implicit none type(dictionary) :: caps integer :: i ! create a character string dictionary call caps%set(’A’,’aye’) call caps%set(’B’,’bee’) call caps%set(’C’,’see’) call caps%set(’D’,’dee’) ! show current dictionary write(*,101)(trim(caps%key(i)),trim(caps%value(i)),i=1,size(caps%key)) ! delete dictionary entries call caps%del(’A’) call caps%del(’C’) call caps%del(’z’) ! a noop as there is no key of ’z’ ! show current dictionary write(*,101)(trim(caps%key(i)),trim(caps%value(i)),i=1,size(caps%key))Results101 format (1x,*(a,"=’",a,"’",:,",")) end program demo_del
> D=’dee’,C=’see’,B=’bee’,A=’aye’ > D=’dee’,B=’bee’
John S. Urban
Public Domain
Nemo Release 3.1 | del (3) | February 23, 2025 |
get(3f) - [M_list::dictionary::OOPS] get value of key-value pair in a dictionary given key (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
type(dictionary) :: dict
character(len=*),intent(in) :: key character(len=*),intent(in) :: VALUEvalue=dict%get(key)
get a value given a key from a key-value dictionary
If key is not found in dictionary , return a blank
DICT is the dictionary. KEY key name VALUE value associated with key
Sample program:
program demo_get use M_list, only : dictionary implicit none type(dictionary) :: table character(len=:),allocatable :: val integer :: iResultscall table%set(’A’,’value for A’) call table%set(’B’,’value for B’) call table%set(’C’,’value for C’) call table%set(’D’,’value for D’) call table%set(’E’,’value for E’) call table%set(’F’,’value for F’) call table%set(’G’,’value for G’)
write(*,*)’A=’,table%get(’A’) write(*,*)’B=’,table%get(’B’) write(*,*)’C=’,table%get(’C’) write(*,*)’D=’,table%get(’D’) write(*,*)’E=’,table%get(’E’) write(*,*)’F=’,table%get(’F’) write(*,*)’G=’,table%get(’G’) write(*,*)’H=’,table%get(’H’)
end program demo_get
> A=value for A > B=value for B > C=value for C > D=value for D > E=value for E > F=value for F > G=value for G > H=
John S. Urban
Public Domain
Nemo Release 3.1 | get (3) | February 23, 2025 |
ifdef(3f) - [M_list::dictionary::OOPS] return whether name is present in dictionary or not (LICENSE:PD)
Synopsis
Description
Options
Returns
Examples
Author
License
type(dictionary) :: dict
character(len=*),intent(in) :: key logical :: valuevalue=dict%ifdef(key)
determine if name is already defined in dictionary or not
DICT is the dictionary. KEY key name
VALUE [char46]FALSE. if name not defined, .TRUE if name is defined.
Sample program:
program demo_ifdef use M_list, only : dictionary implicit none type(dictionary) :: table character(len=:),allocatable :: val integer :: iResults:call table%set(’A’,’value for A’) call table%set(’B’,’value for B’) call table%set(’C’,’value for C’) call table%set(’D’,’value for D’) call table%set(’E’,’value for E’) call table%set(’F’,’value for F’) call table%set(’G’,’value for G’) call table%del(’F’) call table%del(’D’)
write(*,*)’A=’,table%ifdef(’A’) write(*,*)’B=’,table%ifdef(’B’) write(*,*)’C=’,table%ifdef(’C’) write(*,*)’D=’,table%ifdef(’D’) write(*,*)’E=’,table%ifdef(’E’) write(*,*)’F=’,table%ifdef(’F’) write(*,*)’G=’,table%ifdef(’G’) write(*,*)’H=’,table%ifdef(’H’)
end program demo_ifdef
> A= T > B= T > C= T > D= F > E= T > F= F > G= T > H= F
John S. Urban
Public Domain
Nemo Release 3.1 | ifdef (3) | February 23, 2025 |
insert(3f) - [M_list] insert entry into a string array at specified position (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
subroutine insert(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value character(len=:)|doubleprecision|real|integer,intent(in) :: list(:) integer,intent(in) :: place
Insert a value into an allocatable array at the specified index. The list and value must be of the same type (CHARACTER, DOUBLEPRECISION, REAL, or INTEGER)
list is the list array. Must be sorted in descending order. value the value to place in the array PLACE is the subscript that the entry should be placed at
Find if a string is in a sorted array, and insert the string into the list if it is not present ...
program demo_insert use M_sort, only : sort_shell use M_list, only : locate, insert implicit none character(len=:),allocatable :: arr(:) integer :: iResultsarr=[character(len=20) :: ’’, ’ZZZ’, ’aaa’, ’b’, ’xxx’ ] ! make sure sorted in descending order call sort_shell(arr,order=’d’) ! add or replace values call update(arr,’b’) call update(arr,’[’) call update(arr,’c’) call update(arr,’ZZ’) call update(arr,’ZZZ’) call update(arr,’ZZZZ’) call update(arr,’’) call update(arr,’z’)
contains subroutine update(arr,string) character(len=:),allocatable :: arr(:) character(len=*) :: string integer :: place, end
end=size(arr) ! find where string is or should be call locate(arr,string,place) ! if string was not found insert it if(place.lt.1)then call insert(arr,string,abs(place)) endif ! show array end=size(arr) write(*,’("array is now SIZE=",i0,1x,*(a,","))’)end,(trim(arr(i)),i=1,end)
end subroutine update end program demo_insert
> array is now SIZE=5 xxx,b,aaa,ZZZ,, > array is now SIZE=6 xxx,b,aaa,[,ZZZ,, > array is now SIZE=7 xxx,c,b,aaa,[,ZZZ,, > array is now SIZE=8 xxx,c,b,aaa,[,ZZZ,ZZ,, > array is now SIZE=9 xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,, > array is now SIZE=10 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,ZZ,,
1989,2017 John S. Urban
Public Domain
Nemo Release 3.1 | insert (3) | February 23, 2025 |
locate(3f) - [M_list] finds the index where a string is found or should be in a sorted array (LICENSE:PD)
Synopsis
Description
Options
Returns
Examples
Author
License
subroutine locate(list,value,place,ier,errmsg)
character(len=:)|doubleprecision|real|integer,allocatable :: list(:) character(len=*)|doubleprecision|real|integer,intent(in) :: value integer, intent(out) :: PLACEinteger, intent(out),optional :: IER character(len=*),intent(out),optional :: ERRMSG
LOCATE(3f) finds the index where the VALUE is found or should be found in an array. The array must be sorted in descending order (highest at top). If VALUE is not found it returns the index where the name should be placed at with a negative sign.
The array and list must be of the same type (CHARACTER, DOUBLEPRECISION, REAL,INTEGER)
VALUE the value to locate in the list. LIST is the list array.
PLACE is the subscript that the entry was found at if it is greater than zero(0). If PLACE is negative, the absolute value of PLACE indicates the subscript value where the new entry should be placed in order to keep the list alphabetized.
IER is zero(0) if no error occurs. If an error occurs and IER is not present, the program is stopped. ERRMSG description of any error
Find if a string is in a sorted array, and insert the string into the list if it is not present ...
program demo_locate use M_sort, only : sort_shell use M_list, only : locate implicit none character(len=:),allocatable :: arr(:) integer :: iResultsarr=[character(len=20) :: ’’, ’ZZZ’, ’aaa’, ’b’, ’xxx’ ] ! make sure sorted in descending order call sort_shell(arr,order=’d’)
call update(arr,’b’) call update(arr,’[’) call update(arr,’c’) call update(arr,’ZZ’) call update(arr,’ZZZZ’) call update(arr,’z’)
contains subroutine update(arr,string) character(len=:),allocatable :: arr(:) character(len=*) :: string integer :: place, plus, ii, end ! find where string is or should be call locate(arr,string,place) write(*,*)’for "’//string//’" index is ’,place, size(arr) ! if string was not found insert it if(place.lt.1)then plus=abs(place) ii=len(arr) end=size(arr) ! empty array if(end.eq.0)then arr=[character(len=ii) :: string ] ! put in front of array elseif(plus.eq.1)then arr=[character(len=ii) :: string, arr] ! put at end of array elseif(plus.eq.end)then arr=[character(len=ii) :: arr, string ] ! put in middle of array else arr=[character(len=ii) :: arr(:plus-1), string,arr(plus:) ] endif ! show array write(*,’("SIZE=",i0,1x,*(a,","))’)end,(trim(arr(i)),i=1,end) endif end subroutine update end program demo_locate
> for "b" index is 2 5 > for "[" index is -4 5 > SIZE=5 xxx,b,aaa,[,ZZZ, > for "c" index is -2 6 > SIZE=6 xxx,c,b,aaa,[,ZZZ, > for "ZZ" index is -7 7 > SIZE=7 xxx,c,b,aaa,[,ZZZ,, > for "ZZZZ" index is -6 8 > SIZE=8 xxx,c,b,aaa,[,ZZZZ,ZZZ,, > for "z" index is -1 9 > SIZE=9 z,xxx,c,b,aaa,[,ZZZZ,ZZZ,,
1989,2017 John S. Urban
Public Domain
Nemo Release 3.1 | locate (3) | February 23, 2025 |
remove(3f) - [M_list] remove entry from an allocatable array at specified position (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
subroutine remove(list,place)
character(len=:)|doubleprecision|real|integer,intent(inout) :: list(:) integer, intent(out) :: PLACE
Remove a value from an allocatable array at the specified index. The array is assumed to be sorted in descending order. It may be of type CHARACTER, DOUBLEPRECISION, REAL, or INTEGER.
list is the list array. PLACE is the subscript for the entry that should be removed
Sample program
program demo_remove use M_sort, only : sort_shell use M_list, only : locate, remove implicit none character(len=:),allocatable :: arr(:) integer :: i integer :: endResultsarr=[character(len=20) :: ’’,’ZZZ’,’Z’,’aaa’,’b’,’b’,’ab’,’bb’,’xxx’ ] ! make sure sorted in descending order call sort_shell(arr,order=’d’)
end=size(arr) write(*,’("SIZE=",i0,1x,*(a,","))’)end,(trim(arr(i)),i=1,end) call remove(arr,1) end=size(arr) write(*,’("SIZE=",i0,1x,*(a,","))’)end,(trim(arr(i)),i=1,end) call remove(arr,4) end=size(arr) write(*,’("SIZE=",i0,1x,*(a,","))’)end,(trim(arr(i)),i=1,end)
end program demo_remove
> SIZE=9 xxx,bb,b,b,ab,aaa,ZZZ,Z,, > SIZE=8 bb,b,b,ab,aaa,ZZZ,Z,, > SIZE=7 bb,b,b,aaa,ZZZ,Z,,
1989,2017 John S. Urban
Public Domain
Nemo Release 3.1 | remove (3) | February 23, 2025 |
replace(3f) - [M_list] replace entry in a string array at specified position (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
subroutine replace(list,value,place)
character(len=*)|doubleprecision|real|integer,intent(in) :: value character(len=:)|doubleprecision|real|integer,intent(in) :: list(:) integer, intent(out) :: PLACE
replace a value in an allocatable array at the specified index. Unless the array needs the string length to increase this is merely an assign of a value to an array element.
The array may be of type CHARACTER, DOUBLEPRECISION, REAL, or INTEGER. It is assumed to be sorted in descending order without duplicate values.
The value and list must be of the same type.
VALUE the value to place in the array LIST is the array. PLACE is the subscript that the entry should be placed at
Replace key-value pairs in a dictionary
program demo_replace use M_list, only : insert, locate, replace ! Find if a key is in a list and insert it ! into the key list and value list if it is not present ! or replace the associated value if the key existed implicit none character(len=20) :: key character(len=100) :: val character(len=:),allocatable :: keywords(:) character(len=:),allocatable :: values(:) integer :: i integer :: place call update(’b’,’value of b’) call update(’a’,’value of a’) call update(’c’,’value of c’) call update(’c’,’value of c again’) call update(’d’,’value of d’) call update(’a’,’value of a again’) ! show array write(*,’(*(a,"==>",a,/))’)& &(trim(keywords(i)),trim(values(i)),i=1,size(keywords))end program demo_replacecall locate(keywords,’a’,place) if(place.gt.0)then write(*,*)’The value of "a" is ’,trim(values(place)) else write(*,*)’"a" not found’ endif
contains subroutine update(key,val) character(len=*),intent(in) :: key character(len=*),intent(in) :: val integer :: place
! find where string is or should be call locate(keywords,key,place) ! if string was not found insert it if(place.lt.1)then call insert(keywords,key,abs(place)) call insert(values,val,abs(place)) else ! replace call replace(values,val,place) endif
end subroutine update
Results
> d==>value of d > c==>value of c again > b==>value of b > a==>value of a again
1989,2017 John S. Urban
Public Domain
Nemo Release 3.1 | replace (3) | February 23, 2025 |
set(3f) - [M_list::dictionary::OOPS] add or replace a key-value pair in a dictionary (LICENSE:PD)
Synopsis
Description
Options
Examples
Author
License
type(dictionary) :: dict
character(len=*),intent(in) :: key character(len=*),intent(in) :: VALUEcall dict%rep(key,value)
Add or replace a key-value pair in a dictionary.
DICT is the dictionary. key key name VALUE value associated with key
Add or replace a key and value pair in a dictionary
program demo_set use M_list, only : dictionary implicit none type(dictionary) :: dict integer :: iResultscall dict%set(’A’,’b’) call dict%set(’B’,’^’) call dict%set(’C’,’ ’) call dict%set(’D’,’c’) call dict%set(’E’,’ZZ’) call dict%set(’F’,’ZZZZ’) call dict%set(’G’,’z’) call dict%set(’A’,’new value for A’)
write(*,’(*(a,"==>","[",a,"]",/))’) & & (trim(dict%key(i)), & & dict%value(i)(:dict%count(i)), & & i=1,size(dict%key))
end program demo_set
> G==>[z] > F==>[ZZZZ] > E==>[ZZ] > D==>[c] > C==>[] > B==>[^] > A==>[new value for A]
John S. Urban
Public Domain
Nemo Release 3.1 | set (3) | February 23, 2025 |