user3680688
user3680688

Reputation: 426

get coordinates of value in 2D array

I want to get the coordinates of every occurrence of an object stored in an array of arrays. If I have an array:

array = [["foo", "bar", "lobster"], ["camel", "trombone", "foo"]]

and an object "foo", I want to get:

[[0,0], [1,2]]

The following will do this, but it's elaborate and ugly:

array.map
.with_index{
  |row,row_index| row.map.with_index {
    |v,col_index| v=="foo" ? [row_index,col_index] : v
  }
}
.flatten(1).find_all {|x| x.class==Array}

Is there a more straightforward way to do this? This was asked before, and produced a similarly inelegant solution.

Upvotes: 1

Views: 516

Answers (3)

Cary Swoveland
Cary Swoveland

Reputation: 110745

Another way:

array = [["foo", "bar", "lobster"], ["camel", "trombone", "foo"],
         ["goat", "car", "hog"], ["foo", "harp", "foo"]]

array.each_with_index.with_object([]) { |(a,i),b|
   a.each_with_index { |s,j| b << [i,j] if s == "foo" } }
   #=> [[0,0], [1,2], [3,0], [3,2]

Upvotes: 2

sawa
sawa

Reputation: 168239

It's better to work with flat arrays.

cycle = array.first.length
#=> 3
array.flatten.to_enum.with_index
.select{|e, i| e == "foo"}
.map{|e, i| i.divmod(cycle)}
#=> [[0, 0], [1, 2]]

or

cycle = array.first.length
#=> 3
array = array.flatten
array.each_index.select{|i| array[i] == "foo"}.map{|e, i| i.divmod(cycle)}
#=> [[0, 0], [1, 2]]

Upvotes: 0

tckmn
tckmn

Reputation: 59343

Here's a slightly more elegant solution. I have:

  • Used flat_map instead of flattening at the end
  • Used .each_index.select instead of .map.with_index and then having to strip non-arrays at the end, which is really ugly
  • Added indentation
array.flat_map.with_index {|row, row_idx|
  row.each_index.select{|i| row[i] == 'foo' }.map{|col_idx| [row_idx, col_idx] }
}

Upvotes: 4

Related Questions