Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

please help with array and search!!!

1 view
Skip to first unread message

Bobbyj124

unread,
Nov 19, 2008, 12:47:06 PM11/19/08
to
Given a list of numbers (get the input in an array), find the number
of times each of the numbers appear in the list. Store the output in
a new array and print it.

I.E.

List: 2 4 6 2 4 4 6 7

output: 2 3 2 1

(so the output is saying there are two 2's, three 4's, two 6's, and
one 7)

I believe I should do some kind of sort and a binary search but I'm
unsure of how to code the program. I'm using FORTRAN 95. Please help
if you can asap, thanks!

Dick Hendrickson

unread,
Nov 19, 2008, 1:03:11 PM11/19/08
to
Look at the COUNT intrinsic function. It counts the
number of true values in an array expression.
count (test_array == 2)
gives the number of times the 2 occurs.
count (test_array == 3)
gives the number of threes. etc.

You'll probably want to loop from 1 to MAXVAL(test_array) to
look for all of the possible values.

Dick Hendrickson

fj

unread,
Nov 19, 2008, 1:19:03 PM11/19/08
to

As the number of values seems limited, you could use the following
programming :

SUBROUTINE countall(list,output)
INTEGER,INTENT(in) :: list(:)
INTEGER,INTENT(out),ALLOCATABLE :: output(:)
INTEGER :: i
ALLOCATE(output(maxval(list)))
output=0
DO i=1,SIZE(list)
output(list(i))=output(list(i))+1
ENDDO
END SUBROUTINE

Now, if you print values of "output" non equal to zero, you get
exactly what you want.


Bobbyj124

unread,
Nov 19, 2008, 1:32:32 PM11/19/08
to

Here's what I have so far. I am able to get any amount of numbers to
sort. Now I just need to do some sort of search and sort technique,
but I'm confused on where to go from here:

PROGRAM SELECTION_SORT

INTEGER,DIMENSION(:),ALLOCATABLE :: ITEM
INTEGER :: numitems,Allocatestatus

PRINT *,"Enter size of list"
READ *,numitems

!Allocating a run time array
ALLOCATE(ITEM(numitems),STAT = Allocatestatus)
IF(Allocatestatus /= 0) STOP

PRINT *,"Enter list to be sorted"
READ *,ITEM

CALL selectionsort(ITEM)

PRINT *,"Sorted list:",ITEM

DEALLOCATE(ITEM)

CONTAINS

SUBROUTINE selectionsort(ITEM)

INTEGER,DIMENSION(:),INTENT(INOUT) :: ITEM
INTEGER::smallest_item,I,numitems
INTEGER,DIMENSION(1)::Minloc_array

numitems=SIZE(ITEM)

DO I=1,numitems-1

!Finding the smallest element
smallest_item = MINVAL(ITEM(I:numitems))

!Finding the position of the smallest element in the sublist
Minloc_array = MINLOC(ITEM(I:numitems))

!Converting position of smallest element in sublist to its position
in original list
Location_smallest = (I-1)+Minloc_array(1)

!Swapping first element of sublist with smallest element
ITEM(Location_smallest) = ITEM(I)
ITEM(I) = smallest_item

END DO

END SUBROUTINE selectionsort

END PROGRAM SELECTION_SORT

Glen Herrmannsfeldt

unread,
Nov 19, 2008, 2:39:02 PM11/19/08
to
Bobbyj124 wrote:

> Given a list of numbers (get the input in an array), find the number
> of times each of the numbers appear in the list. Store the output in
> a new array and print it.

> List: 2 4 6 2 4 4 6 7

> output: 2 3 2 1

> (so the output is saying there are two 2's, three 4's, two 6's, and
> one 7)

You only say how many, but not what the values are?

> I believe I should do some kind of sort and a binary search but I'm
> unsure of how to code the program. I'm using FORTRAN 95. Please help
> if you can asap, thanks!

I see why you want to sort, but why the binary search?

Say you have an old deck of cards and you want to know how
many of each you have. Sort them, and then just go through
the pile and count them.

Note that someone could give you

1 10000 3 2147483647 -123456 9876543

as input, so you shouldn't try counting for all integer
values. (Or even all REAL values.)

-- glen

baf

unread,
Nov 19, 2008, 3:42:13 PM11/19/08
to

Careful. Looks like a test question.

e p chandler

unread,
Nov 19, 2008, 4:20:09 PM11/19/08
to
> END PROGRAM SELECTION_SORT- Hide quoted text -

I. Sort the data first, then count the length of RUNS of different
data values.

One way to do this is to count items UNTIL the item changes. When that
happens, print out the count. But yuu have to handle the "edge case".
The first item. The last item. You could cheat and add an item after
the list equal to the last item's value+1.

1 1 2 2 3 [4]
# # #
2 2 1

run_length = 1
for i=1 to number_of_items
if item[i] <> item[i+1] then
add run_length to output list
run_length = 1
else
increment run_length
end if
next i

This is actually a fairly standard problem in business data
processing. It's called a "control break". You print total sales, for
example, when the salesman changes (if sorted first on salesman) or
the list is exhausted.

For specialized cases it's easier to compute a frequency historgrm of
the data values, and print out the counts when they are > 0.

-- e

Glen Herrmannsfeldt

unread,
Nov 19, 2008, 4:37:02 PM11/19/08
to
e p chandler wrote:
(snip)

> I. Sort the data first, then count the length of RUNS of different
> data values.

> One way to do this is to count items UNTIL the item changes. When that
> happens, print out the count. But yuu have to handle the "edge case".
> The first item. The last item. You could cheat and add an item after
> the list equal to the last item's value+1.

This is done in many fast sorting and searching algorithms, so
it shouldn't necessarily be considered cheating. In this case,
though, it is possible that there isn't a (last value)+1,
so that might not be a good choice.

For speeding up algorithms, it speeds up the inner loop
(only one test is needed instead of two) but complicates the
outer loop if you don't have a value that is always greater
than any possible input value. A reasonably tradeoff.

-- glen

Bobbyj124

unread,
Nov 19, 2008, 8:13:37 PM11/19/08
to

it only needs to work for integers 0 thru 9. I suppose the search
might not be necessary, but I still don't know the best way to do a
count and get it to print an array.

Bobbyj124

unread,
Nov 19, 2008, 8:15:32 PM11/19/08
to

its actually just a practice question, but knowing how to do it will
help me on the exam

Glen Herrmannsfeldt

unread,
Nov 19, 2008, 8:37:01 PM11/19/08
to
Bobbyj124 wrote:
(snip)

> it only needs to work for integers 0 thru 9. I suppose the search
> might not be necessary, but I still don't know the best way to do a
> count and get it to print an array.

In that case, just count them. No need to sort.

Sorting is most useful when the size of the values is relatively
large, though a hash table works about as well.

-- glen

Bobbyj124

unread,
Nov 19, 2008, 9:20:27 PM11/19/08
to

Ok, I tried incorporating this into my program and I'm getting Error
in the SUBROUTINE countall (list, output) line. It says Error:
allocatable array at (1) must have a deferred shape. Can anyone help
me fix this? Here is my code so far:

PROGRAM SELECTION_SORT

INTEGER,DIMENSION(:),ALLOCATABLE :: output(ITEM)
INTEGER :: numitems,Allocatestatus

PRINT *,"Enter size of list"
READ *,numitems

ALLOCATE(output(ITEM),STAT = Allocatestatus)
IF(Allocatestatus /= 0) STOP

PRINT *,"Enter list to be sorted"
READ *,ITEM

CALL countall(list,output)

PRINT *,"Sorted list:",output(ITEM)

DEALLOCATE(ITEM)

CONTAINS

SUBROUTINE selectionsort(ITEM)

INTEGER,DIMENSION(:),INTENT(INOUT) :: ITEM
INTEGER::smallest_item,I,numitems
INTEGER,DIMENSION(1)::Minloc_array

numitems=SIZE(ITEM)

DO I=1,numitems-1

smallest_item = MINVAL(ITEM(I:numitems))

Minloc_array = MINLOC(ITEM(I:numitems))

Location_smallest = (I-1)+Minloc_array(1)

ITEM(Location_smallest) = ITEM(I)
ITEM(I) = smallest_item

END DO

END SUBROUTINE selectionsort

SUBROUTINE countall(list,output)

INTEGER,INTENT(in) :: list(ITEM)
INTEGER,INTENT(out),ALLOCATABLE :: output(ITEM)


INTEGER :: i
ALLOCATE(output(maxval(list)))
output=0
DO i=1,SIZE(list)
output(list(i))=output(list(i))+1
END DO
END SUBROUTINE

END PROGRAM SELECTION_SORT


thanks,

bobby

Richard Maine

unread,
Nov 19, 2008, 9:57:41 PM11/19/08
to
Bobbyj124 <bobby...@gmail.com> wrote:

> It says Error:
> allocatable array at (1) must have a deferred shape.

...
> INTEGER,DIMENSION(:),ALLOCATABLE :: output(ITEM)

You have tried to specify the dimension twice here... and one of those
specifications is wrong.

You can specify the dimension either with the dimension attribute or
after the object name. I personally prefer to do it after the object
name, but that's a matter of personal taste. If you do it in both
places, as you have above, then the specification after the object name
overrides. That can make sense in more complicated cases, but here where
there is only one object, it just means that the dimension attribute is
essentially ignored, which can only serve to confuse matters.

So this ignores the dimension(:) and instead dimensions output to size
ITEM. Well, as the message says, you can't do that. An allocatable array
*MUST* be declared with (:) (for rank 1 anyway); that's the deferred
shape thing. You allocate the actual shape in the allocate statement -
not in the declaration.

Thus

1. Either put the dimension after the object name or in a dimension
attribute, but not both places.

2. WHichever place you put it, it must be (:) instead of (item)


> INTEGER,INTENT(out),ALLOCATABLE :: output(ITEM)

Here you have it in only one of the places, but you don;t have it as
(:).

--
Richard Maine | Good judgment comes from experience;
email: last name at domain . net | experience comes from bad judgment.
domain: summertriangle | -- Mark Twain

Bobbyj124

unread,
Nov 19, 2008, 10:24:42 PM11/19/08
to
On Nov 19, 9:57 pm, nos...@see.signature (Richard Maine) wrote:

Ok I fixed the problem you mentioned in part (2), but I'm not sure
which DIMENSION thing I need to remove for what you called part (1), I
have 3 in my program. Is is the one at the top that needs to be
removed or do i need to remove/change one of them at the bottom in the
subroutine.

Richard Maine

unread,
Nov 19, 2008, 11:02:13 PM11/19/08
to
Bobbyj124 <bobby...@gmail.com> wrote:

> On Nov 19, 9:57 pm, nos...@see.signature (Richard Maine) wrote:
> > Bobbyj124 <bobbyps...@gmail.com> wrote:
> > > It says Error:
> > > allocatable array at (1) must have a deferred shape.
> > ...
> > > INTEGER,DIMENSION(:),ALLOCATABLE :: output(ITEM)
> >
> > You have tried to specify the dimension twice here... and one of those
> > specifications is wrong.

...


> > 1. Either put the dimension after the object name or in a dimension
> > attribute, but not both places.

> Ok I fixed the problem you mentioned in part (2), but I'm not sure


> which DIMENSION thing I need to remove for what you called part (1), I
> have 3 in my program. Is is the one at the top that needs to be
> removed or do i need to remove/change one of them at the bottom in the
> subroutine.

The principle applies to every declaration. Look at each of them. If it
specifies the dimension twice, remove one of the specifications. In the
above-quoted line, the dimension is specified once by the dimension(:)
and again by the (item) after OUTPUT.

If it is declarations for different variables, that's another matter.
Each array variable does need to have its dimension declared some way or
other. The declaration of some other array variable isn't relevant, so
don't remove the dimension specification of a variable because some
other variable had a dimension specification.

Note also that I'm talking only about the declarations. That
specifically does not include the ALLOCATE statements. For an alocatable
array, you have to specify its dimesion as (:) in the declarations. It
then later gets an allocated size from an allocate statement (or any of
several other ways). That thing in the ALLOCATE statement is not a
declaration and is not what I'm talking about.

At a quick scan, I only saw one such duplicate specification.

Bobbyj124

unread,
Nov 19, 2008, 11:58:08 PM11/19/08
to

thanks a lot, that should straighten things out

e p chandler

unread,
Nov 20, 2008, 12:26:05 AM11/20/08
to

"Louis Krupp" <lkr...@pssw.nospam.com.invalid> wrote in message
news:8oCdnf4r0sG7f7nUnZ2dnUVZ_q7inZ2d@indrasnetinc....
> Then you don't need a sort. You don't need an allocatable array.
>
> You need a counter array dimensioned 0:9 and initialized to zero. When
> you read a number, make sure it is in fact an integer between 0 and 9, and
> then increment the corresponding counter. When you're all done, loop
> through the counters and print the index and the counter.
>
> Louis

Louis is absolutely correct in his approach to the problem. But for Bobby,
the problem is at a different level. How do you think of this solution in
the first place? To the un-initiated it looks like a trick. As Goethe once
said (translated) "one sees what one knows".

Arrays have many uses. (As Jon Bentley once said "COBOL programmers tend to
think of arrays as fixed tables.")

Likewise, a bitmap as an array of flags. Some nice and easy sorting
algorithms (like comb-sort) [The moral, don't write a bogo-sort yourself.]
How to generate a random integer in a certain range. How to shuffle a deck
of cards. And so on. Some of these actually turn up as FAQs in this
newsgroup!

-- elliot


0 new messages