One simple way to randomly scramble a list of any type is to create a random permutation of all the index values of the array and then access the original list elements using that list of indices. The list itself can be re-ordered very succintly using array syntax.
Here is a simple example that, given a list size
The resulting random permutation of the indices can then be used to access essentially any type of list in random order.
scramble(3f) - return an integer array prepopulated with the values 1 to size(array) in random order
function scramble( number_of_values )
integer,intent(in) :: number_of_values
Return an integer array of the size specified populated with the numbers 1 to number_of_values in random order.
Sample program and associated function shows a function returning an array, basic random number generation, and using the function results in an array syntax expression.
program demo_scramble
use M_scramble, only : scramble
implicit none
!@(#) print a list of character values in random order several times
! here is a list of character values to use for an example
! it could be a list of any type
character(len=*),parameter :: list(*)=[character(len=5) :: &
'one','two','three','four','five','six','seven','eight','nine','ten']
integer :: I
do i = 1,8 ! use random values as indices to randomize array
write(*,'(*(a,1x))') list(scramble(size(list)))
enddo
end program demo_scramble
ten six eight one four nine two five three seven
three five ten nine one four six seven two eight
four eight ten two seven nine six three one five
three one nine seven ten five two six eight four
two seven nine one four three eight ten five six
three one nine six ten five eight two four seven
four five six eight one ten three nine seven two
three nine four two one seven ten five six eight
module M_scramble
implicit none
private
public scramble
contains
function scramble( number_of_values ) result(array)
!@(#) M_random::scramble(3f): return integer array of random values 1 to N.
integer,intent(in) :: number_of_values
integer,allocatable :: array(:)
integer :: i, j, k, m, n
integer :: temp
real :: u
array=[(i,i=1,number_of_values)]
! The intrinsic RANDOM_NUMBER(3f) returns a real number (or an array
! of such) from the uniform distribution over the interval [0,1). (ie.
! it includes 0 but not 1.).
!
! To have a discrete uniform distribution on
! the integers {n, n+1, ..., m-1, m} carve the continuous distribution
! up into m+1-n equal sized chunks, mapping each chunk to an integer.
!
! One way is:
! call random_number(u)
! j = n + FLOOR((m+1-n)*u) ! choose one from m-n+1 integers
n=1
m=number_of_values
do k=1,2
do i=1,m
call random_number(u)
j = n + FLOOR((m+1-n)*u)
! switch values
temp=array(j)
array(j)=array(i)
array(i)=temp
enddo
enddo
end function scramble