Vector conversion mixed rational integers

Is there (or how could one write) a function that gives me this vector [0, 1//2, 1, 3//2, 2] from this vector [0//2, 1//2, 2//2, 3//2, 4//2]?

Does

[numerator(r) == 0 ? 0 : denominator(r) == 1 ? Int(r) : r for r in [0//2, 1//2, 2//2, 3//2, 4//2]]

help?

1 Like

HELP!


rng=[numerator(r) == 0 ? 0 : denominator(r) == 1 ? Int(r) : r for r in [n//2 for n in 0:4]]

axes[1].xtickformat = xs->["$(x)π" for x in rng]

this too seems to get there

julia> map(0:4) do n
           try
           Int(n//2)
       catch
           n//2
       end
       end
5-element Vector{Real}:
  0
 1//2
  1
 3//2
  2

I wonder what is the logic applied to solve Int (n // d)

Something like this seems to work too:

x = [0//2, 1//2, 2//2, 3//2, 4//2]
map(u -> (y=floor(Int,u); u == y ? y : u), x)

# result:
5-element Vector{Real}:
  0
 1//2
  1
 3//2
  2

Out of curiosity: what’s this for?

From the plot example, it looks like the goal is to build xticks with rational multiples of π.

There were probably better solutions posted here, but fwiw here is another take on it:

using Plots
x = rationalize.(-2:0.5:3)
r(x) = map(u -> (y=floor(Int,u); u == y ? y : u), x)
l(x) = typeof(x) <: Rational ? "$(x.num)/$(x.den)π" : x==0 ? "0" :
       x==1 ? "π" : x==-1 ? "-π" : "$(x)π"
plot(sin, xlims= π.*extrema(x))
xticks!(x*π, (l∘r).(x))

1 Like

to build xticks with rational multiples of π

Would not be better to immediately convert from Rational to String? You are creating a mixed-types array for no reason in the middle of the way.

1 Like

The reason was to improve the aesthetics of the plot, not performance. Stringing rationals produces double slashes and we should also handle rational integers like 4//2 etc. Any hints?

I was not referring to your solution, mostly because it did not favor legibility so I did not take the time to try to decipher it (looking closely, it also plays with the types without any necessity). I was referring to the post chosen as solution and rocco’s follow-up. My suggestion was to have a single function that took a Rational and returned an String already in the right style, without an conversion to Int step, and just broadcast such function. Like:

julia> x = rationalize.(-2:0.5:3);

julia> function rat2str(r)
           num, den = numerator(r), denominator(r)
           iszero(num) && return "0"
           if isone(den)
               num == -1 && return "-π"
               num ==  0 && return "0"
               num ==  1 && return "π"
               return "$(num)π"
           end 
           return "$(num)/$(den)π"
       end
rat2str (generic function with 1 method)

julia> rat2str.(x)
11-element Array{String,1}:
 "-2π"
 "-3/2π"
 "-π"
 "-1/2π"
 "0"
 "1/2π"
 "π"
 "3/2π"
 "2π"
 "5/2π"
 "3π"

3 Likes

The problem are these fellows:

 "-1π"
 "0π"
 "1π"

But one just need to add some extra conditions.
Thanks.

Edited code from Henrique Becker
function rat2str(r)
    num, den = numerator(r), denominator(r)
    if iszero(num)
       "0"
    elseif isone(den)
       isone(num) ? "π" : isone(-num) ? "-π"  : "$(num)π" 
    else
       "$(num)/$(den)π"
    end
end

x = rationalize.(-2:0.5:3)
rat2str.(x)

 "-2π"
 "-3/2π"
 "-π"
 "-1/2π"
 "0"
 "1/2π"
 "π"
 "3/2π"
 "2π"
 "5/2π"
 "3π"

Maybe there are finicky corner cases, but this is definitely a printing question, and should not take a detour through mixed-type arrays.

Seems like a classic XY-problem.

4 Likes

ha, in the end both of us edited the answers to fit the cases. The OP can now choose the answer in their preferred style.

2 Likes

Hi Henrique, your code is much more elegant, and I learned from it. Cheers.

2 Likes

If you want to learn more about this style, this is basically a extreme application of the Bouncer Pattern. Most articles define it as “make all validations first and then deal with the happy path”, but I use it more generally as “if it is easy to check for and deal with a corner case, do this in the start of the code and in the rest of the code you can assume no corner case”. In this particular code, basically all the code are corner cases of the more general "$(num)/$(den)π" case.

1 Like

The origin of the question stems from the fact that I was unable to populate a vector with the values [0,1 // 2,1,3 // 2,2] by hand because julia automatically transformed them all into rationals.
I just wanted to see how the plot with the “better formatted” ticks looked like.
But then my problem became to understand how to make rational and whole coexist in the same container.
I understood (only AFTER) that for this the type of the container must be Real which is a super-type of rationals and integers (!?).
I know very little about the julia type system and therefore I feel a bit groping.
I have seen the solution you propose and I also believe, as you claim, that it is as natural as possible (as well as very beautiful / elegant) in order to adorn the x axis.
But, as mentioned, in addition to the aesthetic aspect, also figuring out how to make the integers coexist with the fractionals in the same house, which I was not able to do.

Certainly now I am spoiled for choice for the many solutions proposed.
But above all I still learned a little something.

Oh, yes, this is a little disconcerting. You can just do Real[0, 1 // 2, 1, 3 // 2, 2] and have the result you wanted, but there’s nothing in the language that suggests that Julia will try to do an automatic conversion in this situation.

I suppose you find strange that Real is a supertype of integers, but this exactly how math goes (i.e., ℤ ⊂ ℝ, and ℚ ⊂ ℝ). In fact, in Julia:

julia> supertypes(Int)
(Int64, Signed, Integer, Real, Number, Any)

julia> supertypes(Rational)
(Rational, Real, Number, Any)

What I find a little strange that Int is not a subtype of Rational.

Finally, if you start with an empty Vector, the recommended path would be to define the vector like Real[] or Vector{Real}() so at least it is not an Any vector.

1 Like

in fact it is a problem on the X axis (on the Y axis there are only float(real) numbers).
Seriously, you are right to say that I tried to solve a problem (X) in the wrong way and so I self-generated a new problem (Y), which became the problem I posed here, perhaps in an unclear way because I don’t know the structure of the types of julia.
Then I replied that the question arose from trying to solve X and I had the appropriate solutions for problem X.
In the end I got more solutions than I was looking for :grin:

1 Like

NB: this behavior is covered in the manual: Integers mixed with rationals are promoted to rationals

1 Like