I have a problem with a coding execise from Exercism, i habe been trying to solve it for some hours now
I think the problem lies with the connectd == and != as if i tests the statements individually they work out.
Does anyone know how to redefine the == so that the test will go through
The code doesnt clear one of the tests:
function toIntArray(ISBN::String)
dig ="0123456789"
isbn=[]
for i in 1:length(ISBN)
if in(ISBN[i],dig)
append!(isbn,Int(ISBN[i]-48))
elseif ISBN[i]=='X' && (i-length(ISBN))==0
append!(isbn,10)
elseif ISBN[i] =='-'
else
throw(DomainError("Snake on the plane"))
end
end
return(isbn)
end
struct ISBN
isbn::Array{Int}
function ISBN(ISBN::String)
storage=0
isbn = toIntArray(ISBN)
if length(isbn)!= 10
throw(DomainError("tooloongortooshoort"))
end
for i in 1:length(isbn)
storage=storage+ isbn[i]*(11-i)
end
if storage %11 ==0
return(true)
else
throw(DomainError("Thats the wrong number"))
end
end
end
function Base.:(==)(i1::ISBN, i2::ISBN)
return toIntArray(i1)==toIntArray(i2)
end
function Base.:(!=)(i1::ISBN, i2::ISBN)
return toIntArray(i1)!=toIntArray(i2)
end
´´´
The test is
´´´ ISBN("3-598-21508-8") == ISBN("3598215088") != ISBN("3-598-21507-X") ```
(should result in true but results in false)
the ecercise can be found at https://exercism.org/tracks/julia/exercises/isbn-verifier
1 Like
Welcome to the forum!
I don’t want to solve the exercise for you so I will just give you some hints:
- You should check what
ISBN("3-598-21508-8")
returns. It is not of type ISBN
because your constructor (the ISBN
function inside the struct’s definition) never calls new
to actually construct an instance. Have a look at the manual’s section on constructors
- Once you fix that, you will notice that your definitions of
==
and !=
don’t make sense as you didn’t define a method for toIntArray
that takes ISBN
types. So you’ll probably want to rethink what these methods should do.
Come back if you need more hints!
Edit: When you solved it, you can also post your solution and I will give you some pointers how to make it more idiomatic and point out some beginner mistakes i.e. concerning the typing of variables
11 Likes
Hey abraemer,
Great advice
i have succceeded to resolve the problem with your help i think its not the most elegant solution but it works
I changes the constructor from returning the ISBN to new(isbn) # I think that leads to a new instance being created ?
I overloaded the toIntArray function to facilitate it to turn instances of isbn into an IntArray
Thank you very much vor your help!
Here is the current code that manages to pass all the tests:
struct ISBN
isbn::Array{Int}
function ISBN(ISBN::String)
storage=0
isbn = toIntArray(ISBN)
if length(isbn)!= 10
throw(DomainError("tooloongortooshoort"))
end
for i in 1:length(isbn)
storage=storage+ isbn[i]*(11-i)
end
if storage %11 ==0
new(isbn)
else
throw(DomainError("Thats the wrong number"))
end
end
end
function toIntArray(ISBN::String)
dig ="0123456789"
isbn=[]
for i in 1:length(ISBN)
if in(ISBN[i],dig)
append!(isbn,Int(ISBN[i]-48))
elseif ISBN[i]=='X' && (i-length(ISBN))==0
append!(isbn,10)
elseif ISBN[i] =='-'
else
throw(DomainError("Snake on the plane"))
end
end
return(isbn)
end
function toIntArray(isbn::ISBN)
dig ="0123456789"
result=[]
for i in 1:10
append!(result, Int(isbn.isbn[i]))
end
return(result)
end
function Base.:(==)(i1::ISBN, i2::ISBN)
return toIntArray(i1)==toIntArray(i2)
end
Glad my hints where helpful
As promised some comments:
- General logic: your ISBN struct stores the digits of the ISBN, so when you want to compare to instances, you could just compare their arrays directly. Your function
toIntArray(isbn::ISBN)
really just performs a slow copy of the stored array. So you can just do:
Base.:(==)(i1::ISBN, i2::ISBN) = i1.isbn == i2.isbn
- Typing: You annotated the field
isbn
in your ISBN
struct with Array{Int}
which is not a good annotation because Array
denotes a multi-dimensional array and its full type signature carrys the dimension as well. So it would be better (for performance) to write the type as Array{Int, 1}
or just Vector{Int}
which means the same thing. However you could also just leave the type out if you don’t care about performance. Julia does not require you to give fields a type.
- You could shorten the
toIntArray
function a bit using Julia’s isdigit
function and a bit of broadcasting magic (see manual):
function toIntArray(ISBN::String)
digits_string = filter(isdigit, ISBN)
digits = parse.(Int, collect(digits_string)) # note that strings are scalars for broadcasting, so I use collect to turn it into a Vector{Char}
if ISBN[end] == 'X'
push!(digits, 10)
end
return digits
end
- you could consider making the verification of an ISBN its own function. That way you could use that functionality elsewhere and it also would clear up the constructor a bit.
6 Likes
Thanks for the great feedback! I‘ll try to implement it!