Feature #17277
closedMake Enumerator#with_index yield row and col indices for Matrix
Description
Given a matrix:
matrix = Matrix[[0,2,3,4], [6,7,8,9], [1,4,5,8]]
You could get the row and col indices of a matrix using Matrix#each_with_index
:
matrix
.each_with_index { |e, row, col| p [row, col] }
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[2, 0]
[2, 1]
[2, 2]
[2, 3]
You can chain it with other enumerators and access indices within them:
matrix
.each_with_index
.filter_map { |e, row, col| [row, col] if e % 4 == 0}
# => [[0, 0], [0, 3], [1, 2], [2, 1], [2, 3]]
Meanwhile, with_index
after Matrix#each
returns flattened indices, not row or column indices, which does not look right:
matrix
.each.with_index { |e, index| p index }
0
1
2
3
4
5
6
7
8
9
10
11
I feel we should override with_index
for Matrix
so it returns row and column indices.
Updated by marcandre (Marc-Andre Lafortune) about 4 years ago
What about chained enumerators?
matrix.each(:diagonal).each_const(2).with_index do |elem, ?|
It's not clear to me how that could be implemented efficiently, do you have an idea?
Finally, what is the use case?
I would rather add map_with_index
....
Updated by greggzst (Grzegorz Jakubiak) about 4 years ago
I also noticed when combining each_with_index
with inject
it passes element, row_index and col_index
as one argument to the block
Matrix[[1,2,4,5],[7,8,9,2]].each_with_index.inject({}) { |acc, e, row, col| puts "#{acc}, #{e}, #{row}, #{col}"; acc[[e[1],e[2]]] = e[0]; acc }
{}, [1, 0, 0], ,
{[0, 0]=>1}, [2, 0, 1], ,
{[0, 0]=>1, [0, 1]=>2}, [4, 0, 2], ,
{[0, 0]=>1, [0, 1]=>2, [0, 2]=>4}, [5, 0, 3], ,
{[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5}, [7, 1, 0], ,
{[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7}, [8, 1, 1], ,
{[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8}, [9, 1, 2], ,
{[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8, [1, 2]=>9}, [2, 1, 3], ,
=> {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8, [1, 2]=>9, [1, 3]=>2}
marcandre (Marc-Andre Lafortune) wrote in #note-1:
What about chained enumerators?
matrix.each(:diagonal).each_const(2).with_index do |elem, ?|
It's not clear to me how that could be implemented efficiently, do you have an idea?
I tried with refinement for Enumerator in Matrix and use each_with_index
to yield row
and col
index but couldn't get it working...
Finally, what is the use case?
I would like to access matrix indices in enumerable methods to perform some operations based on them.
I would rather add
map_with_index
....
I guess this would be helpful but I think it doesn't give enough flexibility because if you want to use with_index
in select
you don't need the map
part and so on
Updated by nobu (Nobuyoshi Nakada) about 4 years ago
- Status changed from Open to Assigned
- Assignee set to marcandre (Marc-Andre Lafortune)
Updated by greggzst (Grzegorz Jakubiak) about 4 years ago
greggzst (Grzegorz Jakubiak) wrote in #note-2:
I also noticed when combining
each_with_index
withinject
it passeselement, row_index and col_index
as one argument to the blockMatrix[[1,2,4,5],[7,8,9,2]].each_with_index.inject({}) { |acc, e, row, col| puts "#{acc}, #{e}, #{row}, #{col}"; acc[[e[1],e[2]]] = e[0]; acc } {}, [1, 0, 0], , {[0, 0]=>1}, [2, 0, 1], , {[0, 0]=>1, [0, 1]=>2}, [4, 0, 2], , {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4}, [5, 0, 3], , {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5}, [7, 1, 0], , {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7}, [8, 1, 1], , {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8}, [9, 1, 2], , {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8, [1, 2]=>9}, [2, 1, 3], , => {[0, 0]=>1, [0, 1]=>2, [0, 2]=>4, [0, 3]=>5, [1, 0]=>7, [1, 1]=>8, [1, 2]=>9, [1, 3]=>2}
My bad I just figured out that's a case for inject
so it shouldn't be considered in this discussion.
Anyways it'd be good to have with_index
chained to whatever enumerator returning Matrix indices
Updated by sawa (Tsuyoshi Sawada) about 4 years ago
I think the current behaviour is natural. You cannot play around with with_index
since its receiver is Enumerator
, not Matrix
, and the information as a matrix is already gone.
You can retrieve the row and column indices easily from the flattened indices:
matrix.each.with_index{|e, index| p index.divmod(matrix.column_size)}
[0, 0]
[0, 1]
[0, 2]
[0, 3]
[1, 0]
[1, 1]
[1, 2]
[1, 3]
[2, 0]
[2, 1]
[2, 2]
[2, 3]
Updated by greggzst (Grzegorz Jakubiak) about 4 years ago
sawa (Tsuyoshi Sawada) wrote in #note-7:
I think the current behaviour is natural. You cannot play around with
with_index
since its receiver isEnumerator
, notMatrix
, and the information as a matrix is already gone.You can retrieve the row and column indices easily from the flattened indices:
matrix.each.with_index{|e, index| p index.divmod(matrix.column_size)} [0, 0] [0, 1] [0, 2] [0, 3] [1, 0] [1, 1] [1, 2] [1, 3] [2, 0] [2, 1] [2, 2] [2, 3]
I get that but it means performing divmod calculation every time one needs to work row and col indices out. Couldn’t we maybe return a subclass of Enumerator that implements proper with_index for Matrix?
Updated by marcandre (Marc-Andre Lafortune) about 4 years ago
- Status changed from Assigned to Closed
Closing for lack of a viable solution