I’m participating at a C++ course were the instructor gave us a fun programming challenge. I’ve created a modified version in Fortran which is given below. I encourage you to post your full or partial solutions here.
In the C++ version, the “challenging” part is to do everything without a single for loop. It turns out the solutions are incredibly simple by using the right function from the standard template library (STL) and lambdas. E.g. to place the writers born in the 19th century on the top of the table, one solution looks like this:
template< typename Table >
void nineteenth_century_first( Table& table )
{
// TODO: Put those born in the 19th century ('c') first
// without affecting the general order of persons
std::stable_partition(begin(table), end(table),
[](Person const& p){
return p.birth_year >= 1800 && p.birth_year <= 1899;
};
);
}
All the complicated work is done in the stable_partition
routine.
I’m interested to see how far we can get in Fortran.
! writers.f90
!
! Task: Implement the empty subprograms to perform the following operations on a table of persons:
! 1. Print all persons to the screen
! 2. Randomize their order ('r')
! 3. Order them by last name ('l')
! 4. Find the second oldest person as quickly as possible ('2')
! 5. Put those born in the 19th century first ('c')
! 6. Compute the total age of all persons combined ('t')
!
! Inspired by a Modern C++ training course from Klaus Iglberger
!
module person_type
implicit none
type :: person
! TODO: Each person has a firstname, lastname, birth_year,
! and death year.
end type
contains
subroutine print(table)
type(person), intent(in) :: table(:)
! TODO: Print all persons to the screen
! The firstname and lastname should be left-aligned within their own
! columns of width 8 and 13, respectively.
! Also print the birth year, and age of each person in subsequent columns.
end subroutine
subroutine random_order( table )
type(person), intent(inout) :: table(:)
! TODO: Randomize their order ('r')
end subroutine
subroutine order_by_lastname( table )
type(person), intent(inout) :: table(:)
! TODO: Order them by last name ('l')
end subroutine
subroutine find_second_oldest( table )
type(person), intent(inout) :: table(:)
! TODO: Determine the second oldest person as quickly as possible ('2')
! Note that you are allowed to change the order of persons.
! print *, "second oldest = ", ... , ", age = ", ...
end subroutine
subroutine nineteenth_century_first( table )
type(person), intent(inout) :: table(:)
! TODO: Put those born in the 19th century ('c') first
! without affecting the general order of persons
end subroutine
subroutine total_age( table )
type(person), intent(in) :: table(:)
! TODO: Compute the total age of all persons ('t')
! print *, "Total age = ", ...
end subroutine
end module
program main
use person_type
implicit none
type(person), allocatable :: table(:)
character(len=16) :: command
table = [ &
person( "Miguel", "de Cervantes", 1547, 1616 ), &
person( "Charles", "Dickens", 1812, 1870 ), &
person( "George", "Orwell", 1903, 1950 ), &
person( "Ernest", "Hemingway", 1899, 1961 ), &
person( "William", "Shakespear", 1564, 1616 ), &
person( "Leo", "Tolstoy", 1828, 1910 ), &
person( "Scott", "Fitzgerald", 1896, 1940 ), &
person( "Franz", "Kafka", 1883, 1924 ), &
person( "Mark", "Twain", 1835, 1910 ), &
person( "Roald", "Dahl", 1916, 1990 ), &
person( "James", "Joyce", 1882, 1941 ) ]
repeat: do
write(*,'(A)',advance='no') "Enter Command: "
read(*,*) command
command = adjustl(command)
select case(trim(command))
case('r')
call random_order( table )
case('l')
call order_by_lastname( table )
case('2')
call find_second_oldest( table )
case('c')
call nineteenth_century_first( table )
case('t')
call total_age( table )
case default
exit repeat
end select
call print( table )
end do repeat
end program
To compile the program with gfortran use:
gfortran -Wall -o writers writers.f90