1

I have a very large vector in which I want to add the total number of elements as a condition that repeat numbers do not characterize a new element, for example:

V=[0,5,1,8,9,1,1,]

My desired answer would be:5

But I can't think of a way to do that because with the count function I would have to know all the elements of my vector.

count function not works in this case

PierU
  • 1,391
  • 3
  • 15
  • Sorry, I really don't see how you get 6 in the example you give. Could you try explaining it a bit more clearly? – Ian Bush Nov 22 '22 at 18:14
  • Sorry i made a mistake the correct is 5 elements. – Ikaro andrade Nov 22 '22 at 18:19
  • Thank you. Do you know *a priori* what values the elements can take, for instance are they in a certain range, or can they take "any" value? – Ian Bush Nov 22 '22 at 18:24
  • You want [something like this](https://stackoverflow.com/q/44198212/3157076)? – francescalus Nov 22 '22 at 18:39
  • 1
    Create a binary tree, adding elements only where unique. Unless you are unlucky, the time complexity will be O(N logN) and the space complexity O(N). – lastchance Nov 22 '22 at 20:57
  • @lastchance - not so easy to do with Fortran, as pointers are rather messy IMHO. – John Alexiou Nov 24 '22 at 23:27
  • I beg your pardon to disagree, @JohnAlexiou. In my opinion, Fortran is one of the few languages that got Pointers _right_. – Rodrigo Rodrigues Nov 25 '22 at 04:32
  • @RodrigoRodrigues - care to share an example? – John Alexiou Nov 25 '22 at 04:53
  • An example would be too much text for a comment, but in Fortran, pointers always: 1) must be declared as being so; 2) point to a target declared as being so; 3) bind matching type, kind, rank and (+\-) shape; 4) hide the actual memory address, only exposing the value stored; 5) have as alternative "allocatable", when all you want is malloc 6) cannot be aliased (afaik) – Rodrigo Rodrigues Nov 26 '22 at 01:53

2 Answers2

1

FWIW, here's a solution using a tree. No attempt to balance it.

module treemodule
   implicit none

   private
   public numDistinct

   type Node
      integer value
      type(Node), pointer :: left => null(), right => null()
   end type node

   type, public :: Tree
      private
      type(Node), pointer :: root => null()
      integer :: size = 0
   contains
      procedure insert
      procedure clear
      procedure print
      procedure getsize
      procedure, private :: insertNode
      procedure, private :: deleteNode
      procedure, private :: printNode
   end type Tree

contains
   integer function numDistinct( A )
      integer, intent(in) :: A(:)
      integer i
      type(Tree) T
      numDistinct = 3
      do i = 1, size( A )
         call T%insert( A(i) )
      end do
      numDistinct = T%getsize()
      ! Comment out the following if you don't need it ...
      write( *, "(A)", advance="no" ) "Distinct elements: ";  call T%print;   write( *, * )
      call T%clear
   end function numDistinct

   integer function getsize( this )
      class(Tree) this
      getsize = this%size
   end function getsize

   subroutine insert( this, value )
      class(Tree) this
      integer, intent(in) :: value
      call this%insertNode( this%root, value )
   end subroutine insert

   subroutine print( this )
      class(Tree) this
      call this%printNode( this%root )
   end subroutine print

   subroutine clear( this )
      class(Tree) this
      call this%deleteNode( this%root )
   end subroutine clear

   recursive subroutine insertNode( this, ptr, value )
      class(Tree) this
      type(Node), pointer, intent(inout) :: ptr
      integer value
      if ( associated( ptr ) ) then
         if ( value < ptr%value ) then
            call this%insertNode( ptr%left, value )
         else if ( value > ptr%value ) then
            call this%insertNode( ptr%right, value )
         end if
      else
         allocate( ptr, source=Node(value) )
         this%size = this%size + 1
      end if
   end subroutine insertNode

   recursive subroutine deleteNode( this, ptr )
      class(Tree) this
      type(Node), pointer, intent(inout) :: ptr
      if ( associated( ptr ) ) then
         call this%deleteNode( ptr%left  )
         call this%deleteNode( ptr%right )
         deallocate( ptr )
         this%size = this%size - 1
      end if
   end subroutine deleteNode

   recursive subroutine printNode( this, ptr )
      class(Tree) this
      type(Node), pointer, intent(in) :: ptr
      if ( associated( ptr ) ) then
         call this%printNode( ptr%left  )
         write ( *, "( i0, 1x )", advance="no" ) ptr%value
         call this%printNode( ptr%right )
      end if
   end subroutine printNode

end module treemodule

!=======================================================================

program main
   use treemodule
   implicit none
   integer, allocatable :: A(:)
   integer C

   A = [ 0, 5, 1, 8, 9, 1, 1 ]
   C = numDistinct( A )
   write( *, "( 'Number of distinct elements = ', i0 )" ) C

end program main

Distinct elements: 0 1 5 8 9
Number of distinct elements = 5

lastchance
  • 1,436
  • 1
  • 3
  • 12
0

If you don't care about memory and performances (otherwise there are more efficient codes in the link given by Francescalus):

integer function count_unique(x) result(n)
implicit none
integer, intent(in) :: x(:)
integer, allocatable :: y(:)

y = x(:)
n = 0
do while (size(y) > 0)
    n = n+1
    y = pack(y,mask=(y(:) /= y(1)) ! drops all elements that are 
                                   ! equals to the 1st one (included)
end do

end function count_unique
    
PierU
  • 1,391
  • 3
  • 15