Reputation: 897
My code:
details = """'Swift', '2014', 'compiled'; 'Objective-C', '1984', 'compiled'; 'Scala', '2004', 'compiled'"""
println("Reding the following data will make it easier for you to create an array: $details ")
println("How many programming languages would you like to include in your array?")
max_languages = parse(Int16, readline())
struct Language
name::String
appeared::Int16
implementation::String
end
languages = Vector{Language}(undef, max_languages)
for i in 1:max_languages
println("Name of the language?")
name = readline()
println("In what year did the language first appear?")
appeared = parse(Int16, readline())
println("What is the implementation, is it compiled, JIT, or interpreted?")
implementation = readline()
languages[i] = Language(name, appeared, implementation)
end
println(languages)
function calc_age(array)
today::Int16 = 2020
[ array.age : today - array.appeared ]
end
languagesWithAge = map(calc_age, languages)
println(languagesWithAge)
The goal of my code is to create an array of elements of a composite type(Language). In the array called languages one of the fields is appeared(this field is meant to represent the year that a programming language first appeared). In the second array I want this field to be replaced by the field named age (which is supposed to be computed by 2020 - appeared). This job I thought should be done with map(). Once it is done I want to store the second array in a variable called languagesWithAge.
Just to get the age I could do this:
println("How many programming languages would you like to include in your array?")
max_languages = parse(Int16, readline())
struct Language
name::String
appeared::Int16
implementation::String
age::Int16
end
Language(name, appeared, implementation) = Language(name, appeared, implementation, 2020 - appeared)
languages = Vector{Language}(undef, max_languages)
languages[1] = Language("Julia", 2012, "jit")
languages[2] = Language("Python", 1990, "interpreted")
println(languages)
But my objective is to keep the original array and create a new one using map(). I would like to introduce the data, that is the names of the languages, the years of their first appearance, and their implementation only once. Let us imagine that we have the details of a thousand languages to enter manually - can be quite tedious. That's why I want this to be done only once. That is another reason why I thoughtI about using map() - I want to avoid this step:
languages[2] = Language("Python", 1990, "interpreted")
or this:
for i in 1:max_languages
println("Name of the language?")
name = readline()
println("In what year did the language first appear?")
appeared = parse(Int16, readline())
println("What is the implementation, is it compiled, JIT, or interpreted?")
implementation = readline()
languages[i] = Language(name, appeared, implementation)
end
Originally, I wanted languages to be a tuple, but being a newbie, I yet don't know how to create such a tuple.
When I ran the code, after successfully creating languages array, I get the following from Julia:
ERROR: LoadError: type Language has no field age
Stacktrace:
[1] getproperty(::Any, ::Symbol) at ./sysimg.jl:18
[2] calc_age(::Language) at /home/jerzy/ComputerScience/SoftwareDevelopment/MySoftware/MyJulia/age.jl:37
[3] iterate at ./generator.jl:47 [inlined]
[4] _collect at ./array.jl:632 [inlined]
[5] collect_similar(::Array{Language,1}, ::Base.Generator{Array{Language,1},typeof(calc_age)}) at ./array.jl:561
[6] map(::Function, ::Array{Language,1}) at ./abstractarray.jl:1987
[7] top-level scope at none:0
[8] include at ./boot.jl:317 [inlined]
[9] include_relative(::Module, ::String) at ./loading.jl:1044
[10] include(::Module, ::String) at ./sysimg.jl:29
[11] exec_options(::Base.JLOptions) at ./client.jl:266
[12] _start() at ./client.jl:425
in expression starting at /home/jerzy/ComputerScience/SoftwareDevelopment/MySoftware/MyJulia/age.jl:40
Line 40 that Julia's message refers to is:
languagesWithAge = map(calc_age, languages)
It seems clear to me that I cannot achieve my objective without at leats defining another struct. Would creating multidimensional arrays instead of one-dimensional arrays be an alternative? How would you do this?
Upvotes: 1
Views: 105
Reputation: 13800
First of all here's why you're seeing the error:
function calc_age(array)
today::Int16 = 2020
[ array.age : today - array.appeared ]
end
Your function takes an argument array
and then tries to access the field age
of that argument. The problem is that when you do map(calc_age, languages)
, the function is called for each element of the array, not for the array itself (despite you calling the argument array
in the function definition). So what is happening is that the first element of your language array gets passed into calc_age
, the function then tries to access languages[1].age
, i.e. the field age
of the first element in languages
, but since this is a Language
struct as defined in your code it doesn't actually have that field. That is, you're trying to set the value for a field that is not part of your struct
definition.
Here's a somewhat reduced example of what you're trying to achieve I think:
julia> struct Language
name::String
appeared::Int
implementation::String
end
julia> languages = [Language("Julia", 2012, "Julia and C"),
Language("Python", 1983, "C")]
2-element Array{Language,1}:
Language("Julia", 2012, "Julia and C")
Language("Python", 1983, "C")
# Note that we define the function as operating on a single language
julia> calc_age(language; base_year = 2020) = base_year - language.appeared
calc_age (generic function with 1 method)
# Now we can use broadcasting (dot syntax) to apply it to an array
julia> calc_age.(languages)
2-element Array{Int64,1}:
8
37
One thing you didn't specify is where you want the calculated age to go? Age here is sufficiently simple that one possibility would be to add it as information to the Language
struct itself by calculating it automatically upon construction:
julia> struct Language2
name::String
appeared::Int
implementation::String
age::Int
end
julia> Language2(name, appeared, implementation) = Language2(name, appeared, implementation,
2020 - appeared)
Language2
julia> Language2("Julia", 2012, "Julia and C")
Language2("Julia", 2012, "Julia and C", 8)
Upvotes: 3