-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add keys(::Array) and values(::Array) #12811
Conversation
While I can see the analogy with keys and values in dictionaries, I'm wondering what your use case is...? |
In JuMP, we have a macro that returns either an Array, or a custom type that wraps around an Array or Dict. For the custom types, computing |
Also, the docs are written like
so if this isn't added to Base the help entries should probably be updated to be more specific. |
Makes sense, thanks! |
Would that mean that |
I wouldn't hate using |
I agree that Defining something like keys(a::AbstractArray) = eachindex(a)
eachindex(d::Associcative) = keys(d) Seems rather silly though. |
The problem is, neither |
|
eltype{T,N}(::Type{ArrayIterator{T,N}}) = T | ||
|
||
keys(x::Array) = CartesianRange(size(x)) | ||
values(x::Array) = ArrayIterator(x) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
isn't this equivalent to just values(x::Array) = x
? (e.g. an array is its own iterator?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The idea is not to allow mutation of the underlying array with something like values(x)[2] = 3
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we have this at all, I would prefer values(x::AbstractArray) = x
; if the main purpose is to use this as an iterator, then I don't understand why you would need to prevent mutation. for x in values(a)
or for x in a
already doesn't allow mutation (unless x
is mutable, of course).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Its main purpose is for iteration, but that's certainly not the only way it could be used. Maybe this approach is too paternalistic, though.
What would |
isempty(v::ArrayIterator) = isempty(v.array) | ||
eltype{T,N}(::Type{ArrayIterator{T,N}}) = T | ||
|
||
keys(x::Array) = CartesianRange(size(x)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why not keys(x::AbstractArray) = eachindex(x)
?
And since arrays are already iterable, why not just (discussed below)values(x::AbstractArray) = x
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm fine with that as well.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually wait, eachindex(x)
just gives the linear indexing 1:n
. I prefer the multidimensional Cartesian range since you can use the individual components directly:
for I in keys(x)
x[I] += c[I[1]]
end
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
eachindex
chooses the most efficient index iterator for the given array. For Array
and other contiguous arrays (LinearFast()
), that's simply 1:n
. But for SparseMatrixCSC
and other non-contiguous arrays (LinearSlow()
), it's a cartesian range.
@timholy it seems |
So is the proposal to deprecate both |
It makes sense for Using |
@joehuchette my point was more that this seems more ambiguous for anything which can be indexed in more than one way. (DataFrames would tend to follow master, of course.) |
I think DataFrames can be misleading since it's unclear whether you should care about rows or columns. It's not really amenable to any kind of generic programming. |
I've updated the PR to just keys( x::Array) = CartesianRange(size(x))
values(x::Array) = x @timholy I take your point about ambiguity, but I'm not sure it's much of an issue for |
I can see the case for this — there are times when you want an array to serve as a LUT, so you think of the indices more as keys, and want to be able to generically switch to a dictionary if you need. That said, using It seems like a failure of dispatch that |
@mbauman you did a nice job articulating my particular use case: I want to treat an I think the |
This will happen as part of #22907. |
This PR adds methods for
keys
andvalues
forArray
s. Thekeys
implementation is merely aCartesianRange
, while thevalues
implementation uses a new lightweight wrapper around theArray
. I did it this way because just usingvalues(d::Array) = d
means you could change the contents ofd
by what is returned fromvalues
, whilevalues(d::Array) = copy(d)
seemed wasteful. This could potentially be widened toAbstractArray
, but this doesn't seem like the right way to do it for something like a sparse matrix, for example.