Vector ordering

I have the algorithm to order a Vector l(i) with components in increasing order, and also I generated a vector order D(i), which tells me where each component comes from, so then I can go back to the original (disordered) vector.

The order and the order vector are fine, the problem occurs when I want to go back to the original. For some reason it doesn't work, it repeats components of the vector and not in a specific order. I don't realize what it is.

Here is the code:

program order
  implicit none
  integer i,j,k,q
  integer l(7),D(7)
  real x


  do i=1,7
     call random_number (x)
     l(i)=1+FLOOR(13*x)
  enddo
  Write(*,*) "Without order"
  do i=1,7
     Write(*,*) l(i)
  enddo
  do i=1,7
     D(i)=i
  enddo
  
  do i=1,6
     do j=i+1,7
        if(l(i).gt.l(j))then
        k=l(i)
        l(i)=l(j)
        l(j)=k
        q=D(i)
        D(i)=D(j)
        D(j)=q
        endif
     enddo
  enddo

  Write(*,*) "Ordered"


  do i=1,7
     Write(*,*) l(i)
  enddo
  Write(*,*) "Order vector"
   do i=1,7
      Write(*,*) D(i)
   enddo
  do i=1,7
    l(D(i))=l(i)
  enddo
  Write(*,*) "The original vector is"
  do i=1,7
    Write(*,*) l(i)
  enddo

endprogram order

Upvotes: 1

Views: 187

Answers (1)

veryreverie
veryreverie

Reputation: 2981

As @albert points out, because your l(D(i))=l(i) loop overwrites l in-place, you are destroying information as you go. Consider the simple example

nmax = 2
l = [1,2]
D = [2,1]

Unrolling your loop gives

l(D(1))=l(1)
l(D(2))=l(2)

i.e.

l(2)=l(1)
l(1)=l(2)

and tracking the value of l, we see

! l = [1,2]
l(2)=l(1)
! l = [1,1]
l(1)=l(2)
! l = [1,1]

So you either need to make a copy of l before the loop, and work from that, or, as @steve points out, you need to do the whole thing in one operation, using a vector subscript, in which case the whole loop would become

l(D) = l

Indeed, it is possible to simplify most of your code using whole-array operations rather than loops, as e.g.

program order
  implicit none
  integer :: i,j,k,q
  integer, parameter :: nmax=7
  integer :: l(nmax),D(nmax)
  real :: x(nmax)
  
  ! Set `l` to a random vector.
  call random_number(x)
  l = 1+floor(13*x)
  
  write(*,*) "Without order"
  write(*,'(I2)') l
  
  ! Set `D` to [1,2,3,4,5,6,7].
  D = [(i, i=1, nmax)]
  
  ! Sort `l` and `D` together.
  do i=1,nmax-1
    do j=i+1,nmax
      if (l(i) > l(j)) then
        ! Swap `l(i)` and `l(j)`.
        l([i,j]) = l([j,i])
        ! Swap `D(i)` and `D(j)`.
        D([i,j]) = D([j,i])
      endif
    enddo
  enddo

  write(*,*) "Ordered"
  write(*,'(I2)') l
  
  write(*,*) "Order vector"
  write(*,'(I2)') D
  
  ! Unsort `l`.
  l(D) = l
  
  write(*,*) "The original vector is"
  write(*,'(I2)') l
end program order

Upvotes: 3

Related Questions