x = rand(5, 5)
for c in eachcol(x)
c[c .< maximum(x) / 2] .= 0
end
display(x)
This uses a Bool array to index the column, which is very typical in python, less so in Julia but it works. Once you iterate through the individual values in the column, though, you’re down to plain bits types (numbers), which are passed by value, not by reference, hence the e variable doesn’t refer to the memory location in your original x matrix, overwriting its values doesn’t change x itself.
That being said, you don’t even need the eachcol here, as Julia is ace when it comes to matrices:
Note, by the way, that calling maximum(x) inside your innermost loop is horribly inefficient because computing the maximum involves traversing the whole array x, and you are repeating that for every loop iteration — you really want to compute maximum(x) once outside the loops.
Thanks for your replies. I thought I would be able to figure it out on a simple example, but I still cannot make it work, although
c = rand(4)
for i in eachindex(c)
if c[i] < maximum(c) / 2
c[i] = 0
end
end
works fine.
Here is what I want to do eventually:
I have a matrix of type Any with the leftmost columns and topmost rows serving as headers. For each row, I want to nullify elements based on some simple conditions: for example, nullify every subsequent row element that is less that the current one multiplied by 2. Of course, I have to ignore the heading columns.
This is the simplest example, and I’m not sure how I can use boolean index masks here if I want to filter, say, by the name in the top column and values and something else.
Here is my attempt at filtering:
function filter!(table)
for r in eachrow(table[2:end, :])
for i in eachindex(r)
subr = r[i+1:end]
for j in eachindex(subr)
if r[i] > 0 && subr[j] < r[i] * 2
println("It is less")
setindex!(subr, 0, j)
else
println("Not less")
end
end
end
end
return table
end
A = [[Inf "b" "c" "d"]; [-1 2 3 10]; [-2 3 5 10]]
TARGET = [[Inf "b" "c" "d"]; [-1 2 0 10]; [-2 3 0 10]]
# nothing changed
display(filter!(A))
display(A)
Is there limit in nesting of iterators? Or is slicing here should be done via some non-oblious macros to allow mutation?
There the problem is that slices in Julia create new arrays. Thus, here:
for r in eachrow(table[2:end, :])
you are creating a new array when doing table[2:end, :], and thus then forward you won´t be modifying the original table.
Then, here,
subr = r[i+1:end]
the same happens.
Use @view(table[2:end, :]) and @view(r[i+1:end]) and your function will mutate the original arrays. A shortcut to that is adding @views function... for the whole function.
In my case, the solution is simply to ditch this machinery and do it the old-school way, ignoring the linter warnings
function filter!(table)
for i in 2:size(table, 1)
for j in 1:size(table, 2)
current = table[i, j]
for k in (j+1):size(table, 2)
if current > 0 && table[i, k] < current * 2
table[i, k] = 0
end
end
end
end
return table
end
Indeed. Those warnings are there so that people try to write code that works for arrays with indices that do not go from 1 to the length of the array, or the size in each dimension (OffsetArrays.jl in particular).
But if you know your arrays do not have such complications, you don’t need to worry.