Looping over string representation of number in Julia unexpected behaviour - julia

I'm trying to understand why int("0") > 0 evaluates to false while all([int(i) > 0 for i in "0"]) evaluates to true. Interestingly, [all(i != "0" for i in "0"] also evaluates to true.
How can I get my list comprehension to evaluate correctly, that is, catch the "0"?

int is being called with different types, because iterating over a string is giving Char objects, not strings of length 1:
julia> typeof("0")
ASCIIString (constructor with 2 methods)
julia> [typeof(x) for x in "0"]
1-element Array{Type{Char},1}:
Char
and when given a Char, Julia's int is more like Python's ord:
julia> int("0")
0
julia> int("0"[1])
48
which gives rise to what you see:
julia> [int(i) for i in "0"]
1-element Array{Int32,1}:
48
julia> [int(i) > 0 for i in "0"]
1-element Array{Bool,1}:
true
julia> all([int(i) > 0 for i in "0"])
true
There are lots of ways you could get this to behave as you expect, e.g. use parseint or simply convert back to a string:
julia> [parseint(i) for i in "0"]
1-element Array{Int32,1}:
0
julia> [int(string(i)) for i in "0"]
1-element Array{Int32,1}:
0

Related

Julia - How to use Array comprehension with ternary operator to initialize a vector

This is my desired behavior...
result = []
for element in iterable
if(condition)
push!(result, element)
else
continue
end
end
But when using an array comprehension in Julia with a ternary operator, I'm not sure what the analogous "continue" would be aside from using nothing. Which results in undesired Vector{Union{Nothing, ...}}.
result = [(condition ? element : nothing) for element in iterable]
For example:
vec1 = []
for v in -1:1
if(v==0)
push!(vec1,v)
else
continue
end
end
returns
julia> vec1
1-element Vector{Any}:
0
Meanwhile
vec2 = [(v==0 ? v : nothing) for v in -1:1]
returns
julia> vec2 = [(v==0 ? v : nothing) for v in -1:1]
3-element Vector{Union{Nothing, Int64}}:
nothing
0
nothing
instead of just a normal Vector{Int64}
If you want to use an array comprehensions, you can use the if keyword:
julia> [x for x in -2:2 if iseven(x)]
3-element Vector{Int64}:
-2
0
2
If you don't need to use an array comprehension, you can use filter:
julia> filter(iseven, -2:2)
3-element Vector{Int64}:
-2
0
2
It is not possible to use a construct like:
result = [(condition ? element : <SOMETHING>) for element in iterable]
because this will always preserve the length of the input iterable. It is equivalent to a map, but it seems you really want a filter.

Get Type in Array

How can I get the type inside an array?
a = [1,2,3]
I can get the type of a
typeof(a)
Vector{Int64}
but I actually want Int64. First, I thought a newbie work-around could be
typeof(a[1])
Int64
but this is actually not correct, as can be seen here:
a = [1,2,3, missing]
typeof(a)
Vector{Union{Missing, Int64}}
The type of the vector is Union{Missing, Int64}, but the type of the first element is
typeof(a[1])
Int64
So, how do I get the type of the vector/array?
Use the eltype function:
julia> a = [1,2,3]
3-element Array{Int64,1}:
1
2
3
julia> eltype(a)
Int64
julia> a = [1,2,3, missing]
e4-element Array{Union{Missing, Int64},1}:
1
2
3
missing
julia> eltype(a)
Union{Missing, Int64}

How do I check if an array is empty in Julia?

I am trying to see if there's a handy way to check if an array in Julia is empty or not.
In Julia you can use the isempty() function documented here.
julia> a = []
0-element Array{Any,1}
julia> isempty(a)
true
julia> length(a)
0
julia> b = [1]
1-element Array{Int64,1}:
1
julia> isempty(b)
false
Note that I included the length check as well in case that will help your use case.
For arrays one can also simply use a == []. The types are ignored in this comparison (as usual).
julia> a = []
a == []
0-element Array{Any,1}
julia> a == []
true
julia> a == Int[]
true
julia> String[] == Int[]
true
From Julia help:
isempty determines whether a collection is empty (has no elements).
e.g.
julia> isempty([])
true
julia> isempty(())
true

Substitute of "occursin" function to find a string in an Array{String,1}

What I am trying to do is
i = occursin("ENTITIES\n", lines)
i != 0 || error("ENTITIES section not found")
The error information is
ERROR: LoadError: LoadError: MethodError: no method matching occursin(::String, ::Array{String,1})
Closest candidates are:
occursin(::Union{AbstractChar, AbstractString}, ::AbstractString) at strings/search.jl:452
This is a piece of julia v0.6 code. I am using v1.1 now. I am new to julia and don't know what's the proper subsititute function for this. Please help.
You can broadcast orrursin like this (add a . after function name):
julia> x = "abc"
"abc"
julia> y = ["abc", "xyz"]
2-element Array{String,1}:
"abc"
"xyz"
julia> b = occursin.(x, y)
2-element BitArray{1}:
true
false
julia> findall(b)
1-element Array{Int64,1}:
1
julia> findfirst(b)
1
Note that although String can be iterated over it is treated by broadcast as a scalar.
Also it is worth to remember that occursin returns Bool value so that you can use it directly in logical tests e.g. i || error("ENTITIES section not found") in the code from your question.
In order to locate the index in the collection of the occurrence of true in the return value of broadcasted occursin use findall or findfirst functions (there is also findlast). The difference is that findall returns a vector of entries where true is encountered in the collection, while findfirst returns the first such entry only. Also note the difference when you pass all falses to it. findall will return an empty vector and findfirst will return nothing.
If you do not want to retain the vector b in the code above, you can get the indices directly (this should be faster) by passing a predicate as a first argument to findall/findfirst:
julia> findall(t -> occursin(x, t), y)
1-element Array{Int64,1}:
1
julia> findfirst(t -> occursin(x, t), y)
1

Nested list comprehensions in Julia

In python I can do nested list comprehensions, for instance I can flatten the following array thus:
a = [[1,2,3],[4,5,6]]
[i for arr in a for i in arr]
to get [1,2,3,4,5,6]
If I try this syntax in Julia I get:
julia> a
([1,2,3],[4,5,6],[7,8,9])
julia> [i for arr in a for i in arr]
ERROR: syntax: expected ]
Are nested list comprehensions in Julia possible?
This feature has been added in julia v0.5:
julia> a = ([1,2,3],[4,5,6],[7,8,9])
([1,2,3],[4,5,6],[7,8,9])
julia> [i for arr in a for i in arr]
9-element Array{Int64,1}:
1
2
3
4
5
6
7
8
9
List comprehensions work a bit differently in Julia:
> [(x,y) for x=1:2, y=3:4]
2x2 Array{(Int64,Int64),2}:
(1,3) (1,4)
(2,3) (2,4)
If a=[[1 2],[3 4],[5 6]] was a multidimensional array, vec would flatten it:
> vec(a)
6-element Array{Int64,1}:
1
2
3
4
5
6
Since a contains tuples, this is a bit more complicated in Julia. This works, but likely isn't the best way to handle it:
function flatten(x, y)
state = start(x)
if state==false
push!(y, x)
else
while !done(x, state)
(item, state) = next(x, state)
flatten(item, y)
end
end
y
end
flatten(x)=flatten(x,Array(Any, 0))
Then, we can run:
> flatten([(1,2),(3,4)])
4-element Array{Any,1}:
1
2
3
4
You can get some mileage out of using the splat operator with the array constructor here (transposing to save space)
julia> a = ([1,2,3],[4,5,6],[7,8,9])
([1,2,3],[4,5,6],[7,8,9])
julia> [a...]'
1x9 Array{Int64,2}:
1 2 3 4 5 6 7 8 9
Any reason why you're using a tuple of vectors? It's much simpler with arrays, as Ben has already shown with vec. But you can also use comprehensions pretty simply in either case:
julia> a = ([1,2,3],[4,5,6],[7,8,9]);
julia> [i for i in hcat(a...)]
9-element Array{Any,1}:
1
2
⋮
The expression hcat(a...) "splats" your tuple and concatenates it into an array. But remember that, unlike Python, Julia uses column-major array semantics. You have three column vectors in your tuple; is that what you intend? (If they were row vectors — delimited by spaces — you could just use [a...] to do the concatenation). Arrays are iterated through all elements, regardless of their dimensionality.
Don't have enough reputation for comment so posting a modification #ben-hammer. Thanks for the example of flatten(), it was helpful to me.
But it did break if the tuples/arrays contained strings. Since strings are iterables the function would further break them down to characters. I had to insert condition to check for ASCIIString to fix that. The code is below
function flatten(x, y)
state = start(x)
if state==false
push!(y, x)
else
if typeof(x) <: String
push!(y, x)
else
while (!done(x, state))
(item, state) = next(x, state)
flatten(item, y)
end
end
end
y
end
flatten(x)=flatten(x,Array(Any, 0))

Resources