# Julia vs NumPy array comparison

**URL:** <https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238>\
**Category:** New to Julia\
**Tags:** question\
**Created:** [January 24, 2026, 9:23am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238 "2026-01-24T09:23:35Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![nturneroran](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nturneroran/32/220478_2.png) [@nturneroran](https://discourse.julialang.org/u/nturneroran)\
**Post date:** [January 24, 2026, 9:23am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/1 "2026-01-24T09:23:35Z")

</div>

I’m trying Julia for a personal project after working in Python for school. With NumPy  
`a = np.arange(0,10); np.array_equal(a,a.T)` gives `True` as the result. In Julia, `a = range(0, length=10); a == transpose(a)` or `a == a'` give false, and `a .== transpose(a)` gives a matrix with `true` or `1` on the diagonal. Could someone explain what’s going on here? I’m unclear about the differences in the statements, and why the comparisons give different results. Thanks!

---

<div class="post-metadata">

**Author:** ![giordano](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/giordano/32/2166_2.png) [@giordano](https://discourse.julialang.org/u/giordano)\
**Post date:** [January 24, 2026, 9:50am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/2 "2026-01-24T09:50:34Z")

</div>

I don’t know about numpy, but in Julia `a = range(0, length=10)` is a one-dimensional column vector, its transpose is a row vector, and they can’t be equal because they have different shapes. With `a .== a'` you’re roughly checking whether they have equal corresponding elements, the dot is used for [broadcasting](https://docs.julialang.org/en/v1/manual/mathematical-operations/#man-dot-operators)

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 24, 2026, 10:14am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/3 "2026-01-24T10:14:18Z")

</div>

> [@nturneroran](#):
>
> `np.array_equal(a,a.T)` gives `True`

`ndarray.T` or the equivalent `numpy.transpose` mean something different from `transpose` in Julia. NumPy “transposes” the axes of a multidimensional array and reverses the `shape`, so it would do nothing to a vector:

```py
>>> a = np.arange(0, 10)
>>> a
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])
>>> a.T
array([0, 1, 2, 3, 4, 5, 6, 7, 8, 9])

```

In Julia, a vector is conventionally treated as surrogate for a matrix with 1 column, which is a column vector in the linear algebra sense. `transpose` represents a matrix transpose, so it would turn a vector into a row vector:

```julia-auto
julia> a = range(0, length=10)
0:9

julia> transpose(a)
1×10 transpose(::UnitRange{Int64}) with eltype Int64:
 0 1 2 3 4 5 6 7 8 9

```

Julia’s `transpose` doesn’t even work on 3- or higher dimensional arrays, and the erroring method suggests `permutedims` instead, thought that can still turn vectors into row vectors if the permutation isn’t specified.

---

<div class="post-metadata">

**Author:** ![karei](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/karei/32/214809_2.png) [@karei](https://discourse.julialang.org/u/karei)\
**Post date:** [January 24, 2026, 10:24am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/4 "2026-01-24T10:24:00Z")

</div>

### 1. NumPy: a 1D array has no row/column orientation

In NumPy:

```python
import numpy as np

a = np.arange(0, 10)
a.shape # (10,)
a.T.shape # (10,) <-- transpose is a no-op for 1D arrays
np.array_equal(a, a.T) # True

```

A NumPy 1D array has shape `(n,)`, not `(n,1)` or `(1,n)`, so `.T` cannot swap axes (there’s only one axis). That’s why `a` and `a.T` are equal.

### 2. Julia: `transpose`/`'` gives a row vector object

In Julia, a `Vector` is 1D, but Julia’s `transpose` (and `a'`, the adjoint) are defined with linear algebra semantics: they turn a column vector into a _row_ vector (as a lazy wrapper type, not necessarily copying data). Therefore, the shapes/axes don’t match:

```julia
a = collect(range(0, length=10)) # Vector{Int}
a == transpose(a) # false
a == a' # false

```

`a` is a `Vector` with axes `(1:10,)`, while `transpose(a)` behaves like a `1×10` row object with axes `(1:1, 1:10)`. Since `==` for arrays requires matching axes and equal elements, this returns `false`.

### 3. Why `a .== transpose(a)` makes a matrix with a true diagonal

Dot operators broadcast elementwise. Here you’re broadcasting a length-10 vector against a `1×10` row vector, so Julia expands them to a `10×10` result.

### 4. `==` checks axes/shape and compares elements

Julia’s `==` compares values (and for arrays, also requires matching axes). Pointer/object identity is `===`.

If you want something closer to NumPy’s `np.array_equal(a, b)` (notably treating `NaN` values in the same positions as equal), `isequal(a, b)` is typically the closest match:

```julia
isequal(a, b) # matches NaN with NaN in the same positions

```

---

<div class="post-metadata">

**Author:** ![eldee](https://avatars.discourse-cdn.com/v4/letter/e/b5a626/32.png) [@eldee](https://discourse.julialang.org/u/eldee)\
**Post date:** [January 24, 2026, 10:39am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/5 "2026-01-24T10:39:41Z")

</div>

> [@nturneroran](#):
>
> `a .== transpose(a)` gives a matrix with `true` or `1` on the diagonal

Going into more detail about (Julia’s) broadcasting, what’s happening here is that in this broadcast of `Array`s with shapes `(10,)` and `(1, 10)` Julia is first adding implicit trailing singleton dimensions until the number of axes match (`(10, 1)` and `(1, 10)`). Then the singleton dimensions are implicitly filled to matching `(10, 10)` (i.e. in the broadcasting `a` behaves as if it is a `Matrix` `b` of shape `(10, 10)` with `b[i, j] == b[i, 1] == a[i]` for all `j`). Finally, the operation (`==`) is applied elementwise, resulting in a `(10, 10)` binary matrix.

Except for the slightly different semantics of `np.transpose` and Julia’s `transpose`, and accounting for the difference between row and column major ordering (so that a `np.shape` `(10,)` will be expanded using _leading_ singleton dimensions to `(1, 10)`), NumPy works the same (though you need to know that `==` is broadcasting and hence distinct from `np.array_equal`)

```py
>>> a[:, None] == a # (10, 1) and (10,)
array([[ True, False, False, False, False, False, False, False, False,
        False],
       [False, True, False, False, False, False, False, False, False,
        False],
       [False, False, True, False, False, False, False, False, False,
        False],
       [False, False, False, True, False, False, False, False, False,
        False],
       [False, False, False, False, True, False, False, False, False,
        False],
       [False, False, False, False, False, True, False, False, False,
        False],
       [False, False, False, False, False, False, True, False, False,
        False],
       [False, False, False, False, False, False, False, True, False,
        False],
       [False, False, False, False, False, False, False, False, True,
        False],
       [False, False, False, False, False, False, False, False, False,
         True]])

```

(Also, welcome to the Julia community! 🙂 )

---

<div class="post-metadata">

**Author:** ![nturneroran](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/nturneroran/32/220478_2.png) [@nturneroran](https://discourse.julialang.org/u/nturneroran)\
**Post date:** [January 30, 2026, 8:41pm UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/6 "2026-01-30T20:41:50Z")

</div>

Makes a lot of sense! I suppose I hadn’t thought too much about why Numpy would even return true for a vector transpose. Now that you say Julia treats it true to linear algebra rules, I find it weird that Numpy doesn’t! Thanks so much for your help.

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 31, 2026, 3:49am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/7 "2026-01-31T03:49:54Z")

</div>

Julia’s linear algebra treats `AbstractVector` as a column vector and `transpose`s them to row vectors because of mathematical conventions, that is a vector is treated as a column vector by default and row vectors are typically their explicit transposes. But that’s not a cross-language standard.

- MATLAB doesn’t have a distinct vector type to begin with, the lowest dimensional array is a matrix and we must specify column or row vectors explicitly.
- Given one of the inputs is a matrix, FORTRAN 90’s `matmul` treats a 1st input vector as a row vector or a 2nd input vector as a column vector, and the dimension of length 1 in the resulting row or column vector is dropped to make a vector.
- `numpy.matmul` does the same thing as FORTRAN 90.

When a vector isn’t treated per mathematical conventions, we can instead generalize matrix operations to N-dimensional arrays. That straightforwardly results in `numpy.transpose`, and it has precedent in APL’s array transpose (`⍉`). If you want NumPy arrays to be column vectors (higher dimension arrays being row-major doesn’t obstruct underlying linear algebra libraries) and their transposes to be row vectors, you have to make matrices with `numpy.expand_dims(vector, axis=1)`.

---

<div class="post-metadata">

**Author:** ![sylvaticus](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/sylvaticus/32/203883_2.png) [@sylvaticus](https://discourse.julialang.org/u/sylvaticus)\
**Post date:** [January 31, 2026, 5:54am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/8 "2026-01-31T05:54:48Z")

</div>

> [@Benny](#):
>
> In Julia, a vector is conventionally treated as surrogate for a matrix with 1 column,

Not 100% sure about this. I would rather say that a row vector is a matrix with a single row.  
The “issue” is that arrays in Julia have the “dimension” as foundamental part of their definition: a Vector object has 1 dimension, a Matrix has 2 dimensions, and so on (and, by the way, `Vector` and `Matrix` are just name aliases for the parametric type `Array{T,1}` and `Array{T,2}` respectively).  
Conventionally (and the way they are represented/printed/name aliased), the first dimension is the “vertical” one, so 1 d array are interpreted as column vectors, 2 d arrays have also a horizzontal dimension, so a matrix or a row vector has 2 dimensions, and so on..

---

<div class="post-metadata">

**Author:** ![Benny](https://avatars.discourse-cdn.com/v4/letter/b/49beb7/32.png) [@Benny](https://discourse.julialang.org/u/Benny)\
**Post date:** [January 31, 2026, 6:34am UTC](https://discourse.julialang.org/t/julia-vs-numpy-array-comparison/135238/9 "2026-01-31T06:34:33Z")

</div>

Why is this framed as a disagreement, everything you’re saying aligns with what I said.
