получить размерность многомерного массива в ruby - PullRequest
6 голосов
/ 03 марта 2012

Я только начал изучать рубин. Теперь мне нужно выяснить размерность многомерного массива. Я посмотрел ruby-docs для всех методов массива, но не смог найти метод, который возвращает измерение.

Вот пример:

Для [[1, 2],[3,4],[5,6]] размер должен составлять 2.

Для [[[1,2],[2,3]],[[3,4],[5]]] размер должен составлять 3.

Ответы [ 6 ]

6 голосов
/ 03 марта 2012

Простое объектно-ориентированное решение.

class Array
  def depth
    map {|element| element.depth + 1 }.max
  end
end

class Object
  def depth
    0
  end
end
2 голосов
/ 03 марта 2012

Для этого нет встроенной функции, так как может быть несколько определений того, что вы подразумеваете под «размерностью» для массива. Массивы Ruby могут содержать что угодно, включая хэши или другие массивы. Вот почему я считаю, что для этого вам нужно реализовать собственную функцию.

Предполагая, что под измерением вы подразумеваете "самый глубокий вложенный уровень массивов", это должно сработать:

def get_dimension a
  return 0 if a.class != Array
  result = 1
  a.each do |sub_a|
    if sub_a.class == Array
      dim = get_dimension(sub_a)
      result = dim + 1 if dim + 1 > result
    end
  end
  return result
end

РЕДАКТИРОВАТЬ: и так как ruby ​​- отличный язык и позволяет вам делать некоторые интересные вещи, вы также можете сделать get_dimension методом Array:

 class Array
   def get_dimension
   ... # code from above slightly modified
   end
 end
1 голос
/ 03 марта 2012

в простейшем случае

depth = Proc.new do |array|
  depth = 1
  while Array === array.first do
    array = array.first
    depth += 1
  end
  depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth.call(array)
#=> 3

Или этот крошечный рекурсивный метод

def depth(array, depth=1)
  array = array.send(:first)
  Array === array ? depth(array, depth+1) : depth
end

array =  [[[1,2],[2,3]],[[3,4],[5]]]    
depth(array)
#=> 3
0 голосов
/ 07 сентября 2017

Я не был удовлетворен другими решениями, поэтому я написал однострочник, который я на самом деле использовал бы:

def depth(array)
  array.to_a == array.flatten(1) ? 1 : depth(array.flatten(1)) + 1
end

Он сгладит размерность массива 1 в то время, пока он больше не сможет сгладиться, при подсчете размеров.

Почему это лучше?

  • не требует модификации нативных классов (по возможности избегайте этого)
  • не используетметапрограммирование (is_a?, send, respond_to? и т. д.)
  • довольно легко читается
  • также работает с хешами (уведомление array.to_a)
  • на самом деле работает (в отличие от проверки только первой ветки и других глупостей)
0 голосов
/ 28 декабря 2012

Как модификация подхода ТАСС:

class Array
    def depth
        map{ |element| element.is_a?( Vector ) ? element.depth + 1 : 1 }.max 
    end
end

Сохраняет depth как метод Array и не требует добавления метода к Object.

Конечно, это может быть то, что вы хотите, если вы собираетесь позвонить my_object.depth, где вы не знаете заранее, что my_object.class == Array

0 голосов
/ 03 марта 2012

Как насчет:

class Object
    def dimension
        self.class == Array ? 1 + self[0].dimension : 0
    end
end
[[[1,2],[2,3]],[[3,4],[5]]].dimension
#=> 3
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...