# Numpy's list of lists vs. Julia's linear indexing

**URL:** <https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596>\
**Category:** Offtopic\
**Created:** [August 10, 2022, 10:29am UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596 "2022-08-10T10:29:45Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [August 10, 2022, 10:29am UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/1 "2022-08-10T10:29:45Z")

</div>

> [@Julia type displaying change between versions](https://discourse.julialang.org/t/julia-type-displaying-change-between-versions/85029/48):
>
> If Numpy was truly committed to treating matrices and vectors of vectors the same way then `y[0,0]` would be a valid way to index into a vector of vectors and `x[0][0]` would be a valid way to index into a matrix.

I think Numpy _is_ truly committed to this, and that is a good thing. `x[0][0]` actually is a valid index into a matrix, and in general, `a[i1][i2]...[ik] == a[i1,i2,...,ik]`. Much more reasonable and useful than julia’s `a[i]==vec(a)[i]` in my opinion. (`y[0,0]` doesn’t work in the example above, but that constructor is deprecated anyway).

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [August 10, 2022, 3:00pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/2 "2022-08-10T15:00:02Z")

</div>

> [@yha](#):
>
> Much more reasonable and useful than julia’s `a[i]==vec(a)[i]` in my opinion.

Linear indexing is by far the most efficient way to scan through an array. That may not be of much use when your for loops are slow in the first place, but in Julia the for loops are fast enough that the difference between linear and cartesian indexing becomes a major issue. Of course, we could also introduce some kind of wrapper (or unwrapping) that allows linear indexing, but there’s a long tradition of linear indexing into arrays from Fortran and Matlab.

---

<div class="post-metadata">

**Author:** ![Schneeschaufel](https://avatars.discourse-cdn.com/v4/letter/s/a87d85/32.png) [@Schneeschaufel](https://discourse.julialang.org/u/Schneeschaufel)\
**Post date:** [August 10, 2022, 3:24pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/3 "2022-08-10T15:24:28Z")

</div>

I am not sure if numpy is a role model for anything (it was not designed by scientists or experts in the field).

I never learned C properly (but man I wish I had better C knowledge) but I remember they always give the following examples:

1. Implement an n-dimensional array as a flat array consecutive in memory.
2. An n-dimensional array constructed via arrays of pointers (e.g. the rows are represented by a list of pointers and each pointer points to the start of the values of a row).

I always thought the first method must be faster and safer but I am no expert.

---

<div class="post-metadata">

**Author:** ![yha](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yha/32/3502_2.png) [@yha](https://discourse.julialang.org/u/yha)\
**Post date:** [August 10, 2022, 7:58pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/4 "2022-08-10T19:58:14Z")

</div>

> [@StefanKarpinski](#):
>
> Linear indexing is by far the most efficient way to scan through an array.

But why would you have a linear index into an n-dimensional array in the first place? I don’t recall ever finding myself in that situation, and I have never done `a[i::Number]` on an high-dimensional array in Julia except by accident.  
The only reason I can think of to do that, is in the low-level implementation of either multi-dimensional indexing, or of iteration through all elements of the array. User code can just iterate using a `for` loop anyway. Or if iteration should be consistent with one-dimensional indexing (not sure how important this is), do `for x in vec(array)`, which I think is better style anyway.

> [@Julia type displaying change between versions](https://discourse.julialang.org/t/julia-type-displaying-change-between-versions/85029/52):
>
> I always thought the first method must be faster and safer but I am no expert.

It is faster of course, but this choice of memory layout is independent of what `a[i]` does. Numpy also stores arrays consecutively in memory, but still clearly distinguishes `array` from `vec(array)`, and `array[i]` returns an `n-1`-dimensional slice.

---

<div class="post-metadata">

**Author:** ![mbauman](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mbauman/32/31082_2.png) [@mbauman](https://discourse.julialang.org/u/mbauman)\
**Post date:** [August 10, 2022, 9:33pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/5 "2022-08-10T21:33:22Z")

</div>

Yes, Julia and numpy have different semantics here. And yes, folks may have reasons to prefer one over the other. Whether one is more reasonable or useful than the other is indeed quite a matter of personal opinion.

Personally, I don’t think either semantic (list of lists nor linear indexing) is all that great. But, sure, both are useful in different situations. Heck, linear indexing is what you often end up doing with Julia’s `eachindex` (not that it necessarily needs to be that way, but it is that way right now, and it’s not going to change for quite some time).

(Moderator’s note: I know this came up earlier in the [original thread](https://discourse.julialang.org/t/julia-type-displaying-change-between-versions/85029/), but this makes for a decent split point.)

---

<div class="post-metadata">

**Author:** ![jar1](https://avatars.discourse-cdn.com/v4/letter/j/c0e974/32.png) [@jar1](https://discourse.julialang.org/u/jar1)\
**Post date:** [August 10, 2022, 10:56pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/6 "2022-08-10T22:56:38Z")

</div>

> [@StefanKarpinski](#):
>
> Of course, we could also introduce some kind of wrapper (or unwrapping) that allows linear indexing

Is that `vec`?

---

<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:** [August 11, 2022, 12:13am UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/7 "2022-08-11T00:13:23Z")

</div>

> [@yha](#):
>
> But why would you have a linear index into an n-dimensional array in the first place

NumPy does this on a lower level, it just doesn’t expose this to the user like Julia does. Every time you do `a[i1,i2,...,ik]` where all `i` are integers, `(i1,i2,...,ik)` is used to calculate a linear integer index that is then used to get to the element’s address in the linear virtual memory. Julia exposing linear indexing lets users skip this step for a multidimensional array without having to make a view-like Vector like `b = vec(a)`. The less views or view-like objects to work with, the less that can go wrong; for example, if you accidentally `push!` to `b`, `b` _unshares_ its underlying buffer with `a`.

You’re also leaving out something important about NumPy. `a[i1][i2]...[ik] == a[i1,i2,...,ik]`, but the former is quickly discouraged in tutorials because it makes many temporary arrays (for Julians, it’s like making heap-allocated `view`s). `a[i1]` is just syntactic sugar for `a[i1, :, :, ..., :]` in NumPy.

---

<div class="post-metadata">

**Author:** ![StefanKarpinski](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stefankarpinski/32/24_2.png) [@StefanKarpinski](https://discourse.julialang.org/u/StefanKarpinski)\
**Post date:** [August 11, 2022, 6:30pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/8 "2022-08-11T18:30:23Z")

</div>

Maybe, but ideally something that doesn’t involved reshape, which can be a bit sketchy.

---

<div class="post-metadata">

**Author:** ![cjdoris](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/cjdoris/32/213133_2.png) [@cjdoris](https://discourse.julialang.org/u/cjdoris)\
**Post date:** [August 11, 2022, 7:03pm UTC](https://discourse.julialang.org/t/numpys-list-of-lists-vs-julias-linear-indexing/85596/9 "2022-08-11T19:03:42Z")

</div>

You could always have a `LinearIndex` type, analogous with `CartesianIndex`.
