Transpose of an array of Strings

Do you have a suggestion for what the output of

julia> transpose("abc")

should be, and how it would make sense?

1 Like

Also, don’t you really want a vector? In which case I think the best practice is vec(x) or reshape(x, :).

Well, the transpose acts on an Array, and “abc” is not an array.

Transpose(3) returns 3, so I would expect transpose("abc") to return “abc”.

However, [“abc”, “def”] is an array. So I would expect the transpose to return [“abc” “def”] just as transpose([3,4]) returns [3 4].
I also checked the type hierarchy, and I do not believe that Array appears anywhere between String and Any.

What am I missing?

1 Like

Why do I want to use a vector? What is the difference between a vector and a 1D Array? I thought it was a shortcut.

julia> x = ["a string" "another string"]
1×2 Array{String,2}:
 "a string"  "another string"

julia> permutedims(x)
2×1 Array{String,2}:
 "a string"
 "another string"

Notice that the result is still a Array{String, 2}, which is not a Vector i.e. Array{String, 1}

2 Likes

transpose and adjoint are linear algebra operations. If you want to treat your array as a container, use the container operations like reshape, vec or permutedims.

As far as the why goes, the answer is that LinearAlgebra wants to support matrices of matrices and not all LinearAlgebra objects are themselves ::AbstractArrays — so defaulting to a no-op is subtly error prone and defining a bunch of no-op transposes one-by-one is unsatisfactory. I’m not the biggest fan of this myself, but it is what it is.

6 Likes

I have no qualms about “how it is” as long as it is documented. In order to improve my julia programming skills, I find it important to better understand the “why” of certain decisions, which will lead to improved program efficiency by making correct programming choices more often. Thanks for all your input!

Gordon

2 Likes

Good on you. I’ve read this issue through a couple of times for the same reason. Still don’t totally understand all of it (linear algebra is not my first language), but I’ve learned a bunch!

I think transpose(scalar) = scalar makes sense. But a string is a collection, not a scalar, so I don’t think that really works. At the same time it’s not an array. I actually think throwing an error makes sense here.

Looks like your link didn’t copy-paste correctly.

Why not soulmate that the transpose of a collection is a collection?
So, transpose (1:5) should return 1:5.

Because then what you have is an identity function…

True, and whatmis wrong with that? If no harm done, why throw an error? For example, what if I take the transpose of [1:4, 2:6]? I would expect that to work.
Isn’t the transposemofma scalar an identity operator? Why isn’t that a concern?
The transposemofma diagonal matrixmis an identity operator. I have not checked, but I doubt an error exception is thrown.

I am new to Julia, so I might be missing something philosophically.

The thing you’re missing is that julia> 1:5 == [1,2,3,4,5]. Collections are kind of by definition not scalars.

1:5 is a vector, so transposing that returns a transposed vector, similar to a row vector (isomorphic is the word, I think). It would be bad if

(1:5)' * A

suddenly stopped working for appropriately sized matrices. Ranges are AbstractVectors and need to behave accordingly.

1 Like

I thought that collect(1:5) returned [1,2,3,4,5], which is different.
1:5 is an iterator, so I do not see how == is possible. If you are, correct, I indeed
Have a very serious misunderstanding.

Gordon

1:5 is just a clever way of representing [1, 2, 3, 4, 5] without wasting memory. The point is that their behavior should be exactly the same.

This is the purpose of the AbstractVector type family.

This post might help clarify things: https://stackoverflow.com/a/38638838/12486544. It’s a bit out of date (I don’t think === is still an alias for is) but helps explain what == means.

I do not want to sound rude but this is something you can check in half a minute in the REPL, there is no reason to write a comment questioning it and create more noise instead of checking it first.

julia> 1:5 == [1, 2, 3, 4, 5]
true

julia> typeof(1:5)
UnitRange{Int64}

julia> typeof([1, 2, 3, 4, 5])
Array{Int64,1}

julia> 1 == 1.0
true

Objects of different types can be considered equal. And an iterator/range is semantically a collection, even if it is represented by a fixed size object.

1 Like

I understand your point. However, notemthat you cannot domthe following g:

a= 1:5
b = a[2]

However,

a= [1,2,3,4,5]
b= a[2]

Is allowed. Therefore, their behavior is not the same. Would you suggest that they should be the same?

I would submitmthat 1:5 has the behavior of an iterator, which defines the equivalent of the next operator. Collect acts on 1:5 to return a vector. I do not know whether collect acts on more general iterators, go en that in principles, iterators can have infinite length.