i think i made some progress and i am close to finding it.
This is what i have for now :
function nestedsum(t)
total = 0
for i = 1:length(t)
x1=0
for j = 1:length(t[i])
x1 = x1 .+ t[i]
end
total = total .+ x1
end
end
nestedsum(t)
now, for the last part, I got DimensionMismatch(“arrays could not be broadcast to a common size; got a dimension with lengths 2 and 3”) and truthfully, I don’t know how to get over it…
Nice effort AKL.
I think the problem with your code is your use of the broadcast operator.
+ and .+ are different things.
Try the following:
a = 2
b = 3
c = a + b
println(c)
Now try this
a = [1,2,3]
b = [3,4,5]
c = a .+ b
println(c)
There’s also an indexing bug. Your code should look like this:
function nestedsum(t)
total = 0
for i = 1:length(t)
x1 = 0
for j = 1:length(t[i])
#t[i] will get the list inside the list of lists
#t[i][j] will get the item inside the list inside the list of lists
x1 = x1 + t[i][j]
end
total = total + x1
end
return total
end
But what if we told you you could iterate over your collections like the following:
.+ is broadcasted +. Since you should be adding only scalars in this problem, you shouldn’t need to use it. The reason you found you did need it is on this line:
Now let’s do the Julia thing and see if we can make your code simpler, and learn some things in the process.
Do you see any redundancies in your code? For example, do we need to tally the sum of each inner loop in a seperate variable? Or could we just use one variable to count the entire sum(total)?
It doesn’t have to work to be posted :). But your best effort and a description of what you tried is perfectly acceptable. You’re learning something new - perfection isn’t expected. No rush either.
10.1 is a great example to show some of the ways julia lets you handle things. So I’m more than willing to walk you through a bit more. Point isn’t for you to remember everything, but just remember there are alternatives and kind of guide you along a new way of thinking.
You are telling me to use only one variable(total) to compil the code
so
function nestedsum1(t)
for i in t
x1 = 0
for j in i
x1 = x1 + t[i][j] #here, I don't understand I how I can replace the [i][j]
end
x1 #here, if i have only variable, should i simply say that x1 = x1+i?
end
println(x1)
end
Close,
Look at what you are doing in the first loop. You are resetting this value to 0 at each iteration.
Does this will help
function nestedsum1(t)
total = 0.0
for i in t
#i is now a list in t
for j in i
#j is now an item in i (remember i is a list in t)
total = total + j
end
end
println(total)
end
So basically we can iterate over collections/iterables like lists/arrays/etc using in. This will do what we expect - read each collection from the first element to the last element.
The way you originally wrote the code used the indices to iterate over your collections.
Both of these choices are mostly identical but appear a little different in code. One is easier to read, and maybe will reduce human errors, but, a programmer could prefer one or the other based on what they are comfortable with :).
Here’s another fun thing, in Julia we can rewrite nested loops like the following,
function nestedsum1(t)
total = 0.0
for i in t, j in i
total = total + j
end
println(total)
end
Again, this is the same as above but, it’s nice and concise. Maybe a programmer wouldn’t want to do this because it’s a little muddled to read, but very neat.
Again, you don’t have to do any of this, but, knowing your way around loops, broadcasting, etc will help you read other peoples code :).
going further we can introduce another operator
total += j
this is equivalent too total = total + j. but looks neat and saves our fingers some extra work.
I totally agree that it is good to learn to write this using low-level constructs like loops, even though sum(sum, a) is efficient and concise.
One tricky part about explicit loops is making them type-generic—if you are writing flexible libraries, experienced Julia programmers work hard to make the code composable with arbitrary user-defined types…
If you want a loop to work for summing anything efficiently (e.g. complex numbers, matrices, different precisions, unitful values…), then you should initialize your sum to zero(eltype(eltype(a))) instead of 0 or 0.0. (Or better yet, initialize the sum using the type of the first element, in the case of non-empty arrays; this is what sum does if it can in order to handle abstractly typed containers.)
On the other hand, this is not something I would worry about for your first steps in learning Julia. Not all code needs to be generic (or fast)!
Yes, that’s why I said it is even better to use the first element, if the array is non-empty, to initialize the sum. That’s what sum does. If the container is abstractly typed and empty, then the only thing we can currently do is throw an error:
julia> sum(Any[])
ERROR: MethodError: no method matching zero(::Type{Any})
In Julia 1.6 there is an init keyword to specify the accumulation starting point/type (https://github.com/JuliaLang/julia/pull/36188). Generic programming is tricky (but rewarding!).
I think that in this respect, Julia is navigating uncharted territory (unprecedented combination of language featues) but will gradually develop its own solutions. At the moment replicating what language built-ins like collect are doing is tricky, but approaches like