Is a Structure in a Collection

I want to find whether a Structure of Type A is in included in A Collection. In the next step I wanna return this collection form a Collection of a Collection of Type A^^.

struct A
   a = Int
end

a = [A(1), A(2)]
in(a, A(1))

This throws the Error:

ERROR: MethodError: no method matching iterate(::A)
Closest candidates are:
  iterate(::Union{LinRange, StepRangeLen}) at ~/packages/julias/julia-1.7/share/julia/base/range.jl:826
  iterate(::Union{LinRange, StepRangeLen}, ::Integer) at ~/packages/julias/julia-1.7/share/julia/base/range.jl:826
  iterate(::T) where T<:Union{Base.KeySet{<:Any, <:Dict}, Base.ValueIterator{<:Dict}} at ~/packages/julias/julia-1.7/share/julia/base/dict.jl:695
  ...
Stacktrace:
 [1] in(x::Vector{A}, itr::A)
   @ Base ./operators.jl:1282
 [2] top-level scope
   @ REPL[6]:1

I assume I have to implement an iterate function?! How is this done? What needs to be returned?

First things first:

julia> struct A
          a::Int
       end

julia> a = [A(1), A(2)]
2-element Vector{A}:
 A(1)
 A(2)

julia> findfirst(x->x==A(1),a)
1

julia> in(A(1),a)
true
2 Likes

Let us see what this is.

Seems that your question is answered, but this is another interpretation for that question:

julia> struct A a::Int end;

julia> struct B b::Int end;

julia> a = [ B(1), A(2) ]
2-element Vector{Any}:
 B(1)
 A(2)

julia> findfirst(x -> isa(x,A), a)
2


And then maybe the second question is:

julia> a = [ A(1), B(1), A(2) ]
3-element Vector{Any}:
 A(1)
 B(1)
 A(2)

julia> findall(x -> isa(x,A), a)
2-element Vector{Int64}:
 1
 3

julia> a2 = a[findall(x -> isa(x,A), a)]
2-element Vector{Any}:
 A(1)
 A(2)


1 Like

Sorry, my desciption must have been not so clear. What I wanted to do is something similar to:


julia> struct Point{t<:Real}
           row:: t
           col:: t
       end

a = [Point(1, 1), Point(2, 2)]
b = [Point(1, 2), Point(2, 1)]
ab = [a, b]
ab[findfirst(x-> in(x, Point(1, 1), ab)]

From the error message I assume that the in function, applies an iteratertion which is not implemented for this Type “Point”.

for function in its:

in(item, collection)

you use it the other way round.

3 Likes

thanks @oheil

One step at the time: First, the in call is inverted, this works,

julia> a = [Point(1, 1), Point(2, 2)]
2-element Vector{Point{Int64}}:
 Point{Int64}(1, 1)
 Point{Int64}(2, 2)

julia> findfirst(x -> in(Point(1,1), a), a)
1

# and (more reasonably in this case):
julia> findfirst(x -> x==Point(1,1), a)
1

#or (I like this one)
julia> findfirst(isequal(Point(1,1)), a)
1

Now, you have a collection of collections. This command (with the dot: findall.(), will apply the findall operation to each element of the “outer” collection (this is the standard broadcast syntax of Julia):

julia> a = [Point(1, 1), Point(2, 2)];

julia> b = [Point(1, 2), Point(2, 1), Point(1,1) ];

julia> ab = [a, b];

julia> findall.(isequal(Point(1,1)), ab)
2-element Vector{Vector{Int64}}:
 [1]
 [3]

Which is an array of vectors, containing the desired indexes of the elements at for each vector. It that is not what you want, you can use, for example:

julia> filter(isequal(Point(1,1)), reduce(vcat, ab))
2-element Vector{Point{Int64}}:
 Point{Int64}(1, 1)
 Point{Int64}(1, 1)

(where reduce(vcat, ab) flattens the ab array of arrays into a simple vector:

julia> reduce(vcat, ab)
5-element Vector{Point{Int64}}:
 Point{Int64}(1, 1)
 Point{Int64}(2, 2)
 Point{Int64}(1, 2)
 Point{Int64}(2, 1)
 Point{Int64}(1, 1)

2 Likes