MLStackMLSCCafé
 
 
Sign in with GoogleSign in with Google. Opens in new tab
Master Your ML & DSML Interview
2103 Curated Machine Learning, Data Science, Python & LLMs Interview Questions
Answered To Get Your Next Six-Figure Job Offer
👨‍💻 Having Full-Stack & Coding Interview? Check  FullStack.Cafe - 3877 Full-Stack, Coding & System Design Questions and AnswersHaving Full-Stack & Coding Interview? Check 👨‍💻 FullStack.Cafe - 3877 Full-Stack, Coding & System Design Questions and Answers

27 Julia Programming Interview Questions (SOLVED) for ML Engineers

Julia was built for scientific computing, machine learning, data mining, large-scale linear algebra, distributed and parallel computing. It is a flexible dynamic language with performance comparable to traditional statically-typed languages. Julia is also faster than Python by default as it comes with JIT compilation and type declarations. Follow along and check the 27 most common Julia programming interview questions and answers for your next machine learning or data science interview.

Q1: 
What's the advantage of using struct vs mutable struct's composite objects?

Answer

Composite objects declared with struct are immutable; they cannot be modified after construction. This may seem odd at first, but it has several advantages:

  • It can be more efficient. Some structs can be packed efficiently into arrays, and in some cases the compiler is able to avoid allocating immutable objects entirely.
  • It is not possible to violate the invariants provided by the type's constructors.
  • Code using immutable objects can be easier to reason about.

However, an immutable object might contain mutable objects, such as arrays, as fields. Those contained objects will remain mutable; only the fields of the immutable object itself cannot be changed to point to different objects.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q2: 
How to combine two vectors into a matrix?

Problem

Let's assume I have two vectors x = [1, 2] and y = [3, 4]. How to best combine them to get a matrix m = [1 2; 3 4]?

Answer

There different ways to combine the vectors, two approaches are:

  1. reshape each vector:

    julia> m = [reshape(x, 1, :); reshape(y, 1, :)]
    2×2 Matrix{Int64}:
    1  2
    3  4
  2. Using the transpose of each vector.

    julia> m = [transpose(x); transpose(y)]
    2×2 Matrix{Int64}:
    1  2
    3  4  

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q3: 
How to select elements from array in Julia Matching Predicate?

Problem

Given an array a how to select elements that are greater than 4?

julia> a = 2:7
2:7
Answer

There are two solutions:

  • Using Higher-order filtering:

    julia>filter(x -> x > 4, a)
    3-element Vector{Int64}:
    5
    6
    7

    This calls the filter function with the predicate x -> x > 4 (an anonymous function).

  • Broadcasting and indexing: This performs a broadcasting comparision between the elements of a and 4:

    julia>a[a .> 4]
    3-element Vector{Int64}:
    5
    6
    7

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q4: 
What are the differences between Zero-dimensional arrays and Scalars in Julia?

Answer
  • Zero dimensional arrays are arrays of the form Array{T,0}. For instance, A = zeros() is a 0-dimensional array and a mutable container that contains one element, which can be set by A[] = 1.0 and retrieved with A[]. All zero-dimensional arrays have the same size (size(A) == ()), and length (length(A) == 1). But importantly, zero-dimensional arrays are not empty.

  • Scalars are not mutable containers: In particular, if x = 0.0 is defined as a scalar, it is an error to attempt to change its value via x[] = 1.0.. Another difference is that a scalar can participate in linear algebra operations such as 2 * rand(2,2), but the analogous operation with a zero-dimensional array fill(2) * rand(2,2) is an error.

  • Also a scalar x can be converted into a zero-dimensional array containing it via fill(x), and conversely, a zero-dimensional array a can be converted to the contained scalar via a[].


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q5: 
What does an exclamation mark (!) mean after the name of a function in Julia?

Answer

It is a Julia convention to append a bang ! to names of functions that modify one or more of their arguments. This convention warns the user that the function is not pure, i.e., that it has side effects. A function with side effects is useful when you want to update a large data structure or variable container without having all the overhead from creating a new instance.

For example, we can create a function that adds 1 to each element in a vector V, so instead of:

function add_one(V)
    for i in 1:length(V)
        V[i] += 1
    end
    return nothing
end

we use:

function add_one!(V)
    for i in 1:length(V)
        V[i] += 1
    end
    return nothing
end

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q6: 
What does the slat operator (...) do?

Answer

Depending on the context, the slat operator (...) means two different things:

  • In the context of function definitions, ... indicate that the function accepts an arbitrary number of arguments. This can be useful for things where you need to pass an unknown number of arguments and don't want to have to bother constructing an array first before passing it in when working with the function interactively. For example:

    func geturls(urls::Vector)
    # some code to retrieve URL's from the network
    end
    geturls(urls...) = geturls([urls...])
    
    # slightly nicer to type than building up an array first then passing it in.
    geturls("http://google.com", "http://facebook.com")
    
    # when we already have a vector we can pass that in as well since julia has method dispatch
    geturls(urlvector)
  • In the context of working with functions ... can also be used to apply a function to a sequence of arguments. The ... operator causes a single function argument to be split apart into many different arguments when used in the context of a function call. For example, the add_elements function below takes three arguments to be added together, so we use the splat operator ... which takes a collection (often an array, vector, tuple, or range) and converts it into a sequence of arguments:

    add_elements(a, b, c) = a + b + c
    # Output: add_elements (generic function with 1 method)
    
    my_collection = [1, 2, 3]
    add_elements(my_collection...)
    # Output: 6

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q7: 
What is the difference between == and === comparison operators in Julia?

Answer
  • === implements Henry Baker's EGAL predicate: x === y is true when two objects are programmatically indistinguishable – i.e. you cannot write code that demonstrates any difference between x and y. This boils down to the following rules:

    • For mutable values (arrays, mutable composite types), ===checks object identity: x === y is true if x and y are the same object, stored at the same location in memory.
    • For immutable composite types, x === y is true if x and y have the same type –and thus the same structure–, and their corresponding components are all recursively ===.
    • For bits types (immutable chunks of data like Int or Float64), x === y is true if x and y contain exactly the same bits. These rules, applied recursively, define the behavior of ===.
    • Furthermore, the === operator is not overloadable: it is a builtin function with fixed, pre-defined behavior. You cannot extend or change its behavior.
  • == on the other hand, is user-definable or overloaded: it has fallback definitions that give it useful default behavior on user-defined types, but you can change that as you see fit by adding new, more specific methods to == for your types. Also, this operator and implements "abstract value equality", you can think of this as intuitive equality: If two numbers are numerically equal, they are ==. For example:

    julia> 0.5 == 1/2 == 1//2
    true
    julia> 2/3 == 2//3
    false

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q8: 
What's the difference between => and -> operators in Julia?

Answer
  • -> is used to define anonymous functions, For example: x -> x^2 + 2x - 1.
  • => is used to define a pair (e.g., in a dictionary) For example: Dict("A"=>1, "B"=>2).

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q9: 
What's the difference between Array and Vector in Julia?

Answer

The difference is that Vector is a 1-dimensional Array, so when you write e.g. Vector{Int} it is a shorthand to Array{Int, 1}:

julia> Vector{Int64} 
Vector{Int64} (alias for Array{Int64, 1})

So when you call constructors Array([1,2,3]) and Vector([1,2,3]) they internally get translated to the same call Array{Int,1}([1,2,3]) as you passed a vector to them.

Another difference is that Array is a parametric type that has two parameters given in curly braces:

  • the first one is element type (you can access it using eltype).
  • the second one is the dimension of the array (you can access it using ndims).

In Vector there is only one parameter that represent the element type.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q10: 
When would you use :: vs <: operators in types?

Answer

Those operators are particularly important when working with types:

  • The :: operator is used to constrain an object of being of a given type. For example, a::B means “a must be of type B”.

  • The <: operator has a similar meaning, but it’s a bit more relaxed in the sense that the object can be of any subtypes of the given type. For example, A<:B means “A must be a subtype of B”, that is, B is the “parent” type and A is its “child” type.

The primary reason to use these operators is to confirm that the program works the way it is expected. In some cases, providing this extra information can also improve performance.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q11: 
Create a function to count all unique character frequency in a string

Problem

Given some string, (hello, for example). Create a function to count all unique caracters. Expected output:

julia> s = "hello"
julia> counts(s)
'h' => 1
'l' => 2
'e' => 1
'o' => 1

One approach is to create an empty dictionary to gradually store each character as a key and its frequency (counter) as the value, then with the haskey function, we evaluate if some character is repeated and if it is, we increase the counter by 1.

julia> s = "hello"

julia> count_char(s) = begin
          res = Dict{Char, Int}()
          for c in s
              if haskey(res, c)
                res[c] += 1
              else
                res[c] = 1
              end
          end
          res
       end

julia> count_char(s)
Dict{Char, Int64} with 4 entries:
  'h' => 1
  'l' => 2
  'e' => 1
  'o' => 1

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q12: 
How are Positional Arguments different from Keyword Arguments in Julia functions?

Answer
  • A positional argument holds the place for specified value by its ordinal position in the function's argument list. They are typical mandatory, but can be made optional when default values are provided. For example, x and real, imag are positional arguments in these function definitions:

    • sqrt(x) = x^0.5
    • complex(real, imag) = real + imag*im
  • A keyword argument holds the place of a specified value by its name, i.e. can be passed in any order that they are written. They become optional arguments when the default value is not provided. For example, digitcount and digits are keyword arguments in this function definition:

    • roundedstring(x; digitcount) = string(round(x, digits=digitcount))

    The last (rightmost) positional argument comes before the first keyword argument. A semicolon (;) demarks the start of keyword arguments, even when there are no positional arguments. When both kinds of arguments are used, the semicolon separates the positional from the keyword arguments.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q13: 
How do you implement Object-Oriented Model in Julia?

Answer

In Julia, structures roughly corresponds to what is known as classes in other languages. In this aspect, there are two approaches: inheritance and composition:

  • Inheritance: is when a hierarchical structure of types is obtained declaring one type as a subtype of another,
  • Composition: is when you declare one field of a given type as being an object of another composite type. Through this (referenced) object, you then gain access to the fields of the other type.

The preference in the Julia community is to use composition over inheritance. Consider the following example, where you first define a generic Person structure and then two more specific Student and Employee structures:

struct Shoes
  shoesType::String
  colour::String
end

struct Person
  myname::String
  age::Int64
end

struct Student
  p::Person
  school::String
  shoes::Shoes
end

struct Employee
  p::Person
  monthlyIncomes::Float64
  company::String
  shoes::Shoes
end

Instead of using inheritance declaring Student and Employee as subtypes of Person, you use composition to assign a field p of type Person to both of them. It is thanks to this field that you do not need to repeat the fields that are common to both.

Finally, you can then create instances of the specialized type, either by creating the referenced object first or doing that inline in the constructor of the specialized type:

gymShoes = Shoes("gym","white")
proShoes = Shoes("classical","brown")

Marc = Student(Person("Marc",15),"Divine School",gymShoes)
MrBrown = Employee(Person("Brown",45),3200,"ABC Inc.", proShoes)

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q14: 
How to create a function in Julia that saves its own internal state?

Problem

I would like to create a function with an internal state, but I do not want to have to initialize this internal state outside of the function. I want to rely only on calls to this function and I do not want the function to return anything, the following code illustrate the problem:

function foo()
    if @isdefined state
        state += 1
    else
        state = 1  # 1st call: initialize internal state
    end
end

which gives the following expected output:

julia> foo()
1
julia> foo()
2
julia> foo()
3

You can use a let block to create a new local state created in the scope of the assignment, in this way we hide the state.

julia> let state = Ref{Union{Int, Nothing}}(nothing)
         global f
         function f()
           if state[] !== nothing
             state[] += 1
           else
             state[] = 1
           end
           state[]
         end
       end
f (generic function with 2 methods)

which gives the following output:

julia> f()
1

julia> f()
2

julia> f()
3

Note that we need global f just to ensure that the function f is defined in global scope.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q15: 
How to do One-Hot Encoding in Julia?

Problem

I have a dataframe with a columns containing a list of strings (e.g. ["Type A", "Type B", "Type D"]). How does one then performs a one-hot encoding?

Original Dataframe

col1 | col2 |
102  |[a]   |
103  |[a,b] | 
102  |[c,b] |
After One-hot encoding

col1 | col2_a | col2_b | col2_c |
102  |    1   |   0    |    0   |
103  |    1   |   1    |    0   | 
102  |    0   |   1    |    1   |
Answer

Consider:

using DataFrames
df = DataFrame(col1=102:104, col2=[["a"], ["a","b"], ["c","b"]])

# obtain unique elements of the dataframe
ux = unique(reduce(vcat, df.col2))

# perform one hot encoding
transform(df, :col2 .=> [ByRow(v -> x in v) for x in ux] .=> Symbol.(:col2_, ux))

Output:

3 rows × 5 columns

	col1	col2		col2_a	col2_b	col2_c
	Int64	Array…		Bool	Bool	Bool
1	102	["a"]		1	0	0
2	103	["a", "b"]	1	1	0
3	104	["c", "b"]	0	1	1

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q16: 
How to select a random item from a weighted array in Julia?

Answer
  • One simple approach only uses Julia's base library and creates one sample_function:

     sample_function(items, weights) = items[findfirst(cumsum(weights) .> rand())]
     sample_function(["a", 2, 5, "h", "hello", 3], [0.1, 0.1, 0.2, 0.2, 0.1, 0.3])

    Output:

    "h"
  • Another approach is using the StatsBase.jl package, i.e.

     using Pkg
     Pkg.add("StatsBase")  # Only do this once, obviously
     using StatsBase
    
     items = ["a", 2, 5, "h", "hello", 3]
     weights = [0.1, 0.1, 0.2, 0.2, 0.1, 0.3]
     sample(items, Weights(weights))

    Output:

    "h"

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q17: 
What does Type-Stable mean in Julia?

Answer

It means that the type of the output is predictable from the types of the inputs. In particular, it means that the type of the output cannot vary depending on the values of the inputs. The following code is not type-stable:

julia> function unstable(flag::Bool)
           if flag
               return 1
           else
               return 1.0
           end
       end
unstable (generic function with 1 method)

It returns either an Int or a Float64 depending on the value of its argument. Since Julia can't predict the return type of this function at compile-time, any computation that uses it must be able to cope with values of both types, which makes it hard to produce fast machine code.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q18: 
What does the :: operator do?

Answer
  • When appended to an expression computing a value, the :: operator is read as "is an instance of". It can be used anywhere to assert that the value of the expression on the left is an instance of the type on the right:

    • When the type on the right is concrete, the value on the left must have that type as its implementation.
    • When the type is abstract, it suffices for the value to be implemented by a concrete type that is a subtype of the abstract type. If the type assertion is not true, an exception is thrown, otherwise, the left-hand value is returned. For example:

      julia> (1+2)::AbstractFloat
      ERROR: TypeError: in typeassert, expected AbstractFloat, got a value of type Int64
      
      julia> (1+2)::Int
      3
  • When appended to a variable on the left-hand side of an assignment, or as part of a local declaration, :: declares the variable to always have the specified type, like a type declaration in a statically-typed language such as C. For example:

    julia> function foo()
             x::Int8 = 100
             x
         end
    foo (generic function with 1 method)
    
    julia> x = foo()
    100
    
    julia> typeof(x)
    Int8

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q19: 
What is ".==" in Julia? What will be the output of the code snippet?

Problem

Consider:

y = [1,5,5,7,9,8,1,1,2,3,1]
x = sum(y .== 1)  
# Output?
Answer
  • The dot (.) is for vectorized operations: It basically applies your selected operation to each element of your vector.
  • So in the case y .== 1 will check equality to 0 for each element of your vector y, meaning x will be the number of values from y being equal to 1, which is 4.

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q20: 
What's the difference between Hard and Soft scope in Julia?

Answer
Source: mortenpi.eu

The scope of a variable is the region of code within which a variable is visible. Certain constructs in the language introduce scope blocks, which are regions of code that are eligible to be the scope of some set of variables.

There are two main types of scopes in Julia: global scope and local scope, the latter can be nested in soft local scope and hard local scope.

  • Soft local scopes:

    • Are introduced by for-loops, while-loops, comprehensions, try-catch-finally-blocks, and let-blocks.
    • The soft local scope inherits both read and write variables. For example:

      x,y = 0, 1
      for i = 1:10
          x = i + y + 1
      end
      
      julia> x
      12
    • Within soft scopes, the global keyword is never necessary, although allowed.

  • Hard local scopes:

    • Are introduced by function definitions (in all their forms), type & immutable-blocks, and macro-definitions.
    • All variables are inherited from its parent scope.
    • An explicit global is needed to assign to a global variable.
    • Example:

      x,y = 1,2
      function foo()
      x = 2 # assignment introduces a new local
      return x + y # y refers to the global
      end
      
      julia> foo()
      4
      
      julia> x
      1

Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q21: 
What's the difference between Primitive types and Composite types?

Answer

A type of an object, in plain English, refers to the set of characteristics that describe the object. For example, an object of type sheet can be described with its dimensions, its weight, its size, or its color. All values in Julia are true objects belonging to a given type (they are individual “instances” of the given type). Julia's types include:

  • A primitive type is made of a fixed amount of bits (like all numerical types such as Int64, Float64, and Char).

  • A composite type or structure, is an object where its characteristics are described using multiple fields and a variable number of bits. They can be seen as a collection of named fields, an instance of which can be treated as a single value.

Both structures and primitive types can be user-defined and are hierarchically organized. Structures correspond to what is known as classes in other languages.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q22: 
What's the difference between missing, Nothing and NaN in Julia?

Answer
  • nothing (type Nothing): This is the value returned by code blocks and functions that do not return anything. It is a single instance of the singleton type Nothing, and is closer to C-style NULL (sometimes it is referred to as the “software engineer’s null”). Most operations with nothing values will result in a run-type error. In a certain context, it is printed as #NULL.

  • missing (type Missing): Represents a missing value in a statistical sense. There should be a value but you don’t know what it is (so it is sometimes referred to as the “data scientist’s null”). Most operations with missing values will propagate (silently).

  • NaN (type Float64): Represents when an operation results in a Not-a-Number value (e.g., 0/0). It is similar to missing in that it propagates silently rather than resulting in a run-type error.


Having Machine Learning, Data Science or Python Interview? Check 👉 50 Julia Interview Questions

Q23: 
What's the difference between Outer and Inner constructor methods in Julia?

Answer
Join MLStack.Cafe to open this Answer. It's Free!
Sign in with GoogleSign in with Google. Opens in new tab
Join 25k+ Data Scientists Who Trust MLStack.Cafe

Q24: 
Why would you a Macro instead of a regular function?

Answer
Join MLStack.Cafe to open this Answer. It's Free!
Sign in with GoogleSign in with Google. Opens in new tab
Join 25k+ Data Scientists Who Trust MLStack.Cafe

Q25: 
Why would you use the Ref() function?

Answer
Join MLStack.Cafe to open this Answer. It's Free!
Sign in with GoogleSign in with Google. Opens in new tab
Join 25k+ Data Scientists Who Trust MLStack.Cafe

Q26: 
What are Traits? How can you implement it in Julia?

Answer
Unlock MLStack.Cafe to open all answers and get your next figure job offer!
 

Q27: 
Why are Abstract Types useful?

Answer
Unlock MLStack.Cafe to open all answers and get your next figure job offer!
 
 

Amazone runs the internet as we know it. Amazon Web Services (AWS) offers a comprehensive suite of machine learning (ML) services that cater to various needs and expertise levels. Follow along and learn the 23 most common AWS machine-learning intervi...

Azure Machine Learning (Azure ML) is a cloud-based service for creating and managing machine learning solutions. It’s designed to scale, distribute, and deploy machine learning models to the cloud. Follow along and learn the 23 most common Azure Mach...

Hadoop is an open-source big data processing framework. It leverages distributed computing to store and process large datasets in a fault-tolerant manner. According to recent reports, Apache Hadoop is one of the most sought-after big data skills with...

Apache Spark is a unified analytics engine for large-scale data processing. It is built to handle various use cases in big data analytics, including data processing, machine learning, and graph processing. Follow along and learn the 23 most common an...
Scala is a powerful language with functional programming capabilities that can be a good choice for data science, especially in big data and distributed computing scenarios. As an example, Apache Spark, a popular distributed data processing framework...
PyTorch popularity as a Deep Learning framework of choice is on the rise. As of December 2022, 62% of the academic papers were implemented in PyTorch whereas only 4% were for TensorFlow. Follow along and prepare effectively with these key 30 PyTorch ...
The use of Artificial Intelligence (AI) in machine learning and data science enabled advancements in areas such as natural language processing, computer vision, recommendation systems, fraud detection, predictive analytics, and personalized medicine....
Optimization algorithms are extensively used in training machine learning models. Data engineers employ algorithms like gradient descent, stochastic gradient descent, and variants (e.g., Adam, RMSprop) to optimize the model parameters and minimize th...
ChatGPT, an implementation of the GPT (Generative Pre-trained Transformer) model excels in understanding and generating human-like text, making it a powerful tool for NLP tasks. ML engineers and software developers can leverage ChatGPT's capabilities...
Large Language Models (LLMs), such as GPT-3.5, have revolutionized natural language processing by demonstrating the ability to generate human-like text and comprehend context. Follow along to understand the top 27 LLMs-related interview questions and...