Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Initializing an Array to Store Objects

Tags:

julia

In Julia, how does one initialize an array to store mutable structs? For example:

mutable struct Foo
    func # Some function
end

function Bar(param1, param2)
    function nestedFunc(param3)
        return param3
    end

    return Foo(nestedFunc)
end

# Initializing with 0s will throw an error when 
# I attempt to store the struct returned in the Bar call below
arr = zeros(5, 5)    
for i in 1:5
    for j in 1:5
        arr[i, j] = Bar(i, j)
    end
end

I've also tried to initialize an array of type Any, as arr = Array{Any, (5, 5)}, but again, when setting the index I get something like ERROR: LoadError: MethodError: no method matching setindex!

How can I do this, and what is the rationale for this behavior I'm seeing? In Python, I can arbitrarily initialize a list and set almost anything I want within a particular index.

like image 837
rw435 Avatar asked Oct 15 '25 04:10

rw435


2 Answers

You can do what you want if you initialize your array as:

arr = Array{Foo,2}(undef,5,5)

In this example you are creating an array in which each element can be of type Foo, and it has two dimensions. The parameters passed to this "constructor" are undef, which tells that all the elements are not initialized, and the size of the two dimensions. You can check The section Construction and initialization of the Arrays section of the Julia manual.

If you are looking for the flexibility of a python list in which you can put objects of whatever type, you can do

arr = Array{Any,2}(undef,5,5)

In this case, the Any specifies that the elements of the Array can be of any type.

However, you should know that this is probably a bad method if you need performance, as having arrays with elements of type 'Any' prevents Julia from creating efficient code for your arrays.

Why your first example was not working

You were creating an array with elements of type Float64, and you were trying to assing a function to these elements. You cannot change the type of the array on the fly. Having a defined type for the elements, allows julia to have an efficient way of saving things in memory and also allows the compiler to use fast functions when you do operations on arrays. Take a look at the Types section of the Julia manual

Why the second example was not working

This is because you were not using a correct form for the initializer. The correct form is the one I showed.

P.S Are you sure you can do this with numpy arrays?

I just tried

import numpy as np
a = np.zeros(5)
a[0] = 'hello'

and got a type error similar to the one you see in Julia:

ValueError: could not convert string to float: 'hola'
like image 155
aramirezreyes Avatar answered Oct 18 '25 02:10

aramirezreyes


Tip: never use untyped containers unless you really have to (usually you almost never have to)

Here is the correct way to do it (I have shortened bar for readability, function names should start with small letters):


mutable struct Foo
    func::Function
end

function bar(param1, param2)
    nestedFunc(param3) = param3
    return Foo(nestedFunc)
end

And now

julia> myarr = [bar(i,j) for i in 1:3, j in 1:4]
3×4 Array{Foo,2}:
 Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)
 Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)
 Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)  Foo(nestedFunc)

Another option (note that round parenthesis () make a generator and dot . vectorizes the assignment operator):

myarr2 =Matrix{Foo}(undef,3,4)
myarr2 .= (bar(i,j)  for i=1:3, j=1:4)

And the longest option (notet that the container is typed):

myarr3 =Matrix{Foo}(undef,3,4)
for i=1:3, j=1:4
    myarr3 = bar(i,j)
end
like image 34
Przemyslaw Szufel Avatar answered Oct 18 '25 02:10

Przemyslaw Szufel