изящная обработка структур данных (хэши и т. д.) в ruby - PullRequest
0 голосов
/ 16 ноября 2009

Недавно я выполнил задание по классу, где создал действительно хакерскую структуру данных. В итоге я использовал вложенные хэши, что кажется хорошей идеей, но перебирать и управлять ими очень сложно.

Я занимался общими вещами, вроде одного тега, связанного с хешем предметов, которые сопоставляются с ценами и тому подобным. Но некоторые из них становились все сложнее.

Я знаю, что рельсы используют множество более элегантных, наглядных вещей с символами и тому подобным (которые я никогда не использую позорное лицо ), и мне было интересно, как я могу оптимизировать это. Например, если бы у меня были свои вложенные хэши что-то вроде этого

 h["cool"][????][1.2]

Есть ли изящный способ извлечь эти ценности? Может быть, я просто новичок в этом отношении, но я хотел все исправить, прежде чем я начал делать больше вещей. Может быть, я даже ищу что-то другое, например, массив / хэш или что-то в этом роде. Пожалуйста, дайте мне знать!

Ответы [ 4 ]

3 голосов
/ 16 ноября 2009

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

Да, это будет довольно много работы, и да, оно того стоит.

2 голосов
/ 17 ноября 2009

Редактировать: Исправлено, чтобы обеспечить приблизительный путь к элементу. Хотя она не может знать имя переменной.

Попробуйте это:

def iterate_nested(array_or_hash, depth = [], &block)
  case array_or_hash
    when Array:
      array_or_hash.each_with_index do |item, key|
        if item.class == Array || item.class == Hash
          iterate_nested(item, depth + [key], &block)
        else
          block.call(key, item, depth + [key])
        end
      end
    when Hash:
      array_or_hash.each do |key, item|
        if item.class == Array || item.class == Hash
          iterate_nested(item, depth + [key], &block)
        else
          block.call(key, item, depth + [key])
        end
      end
  end
end

Он должен выполнять итерацию на любую необходимую глубину, ограниченную памятью и т. Д., И возвращать ключ, элемент и глубину возвращаемого элемента. Работает как с хешами, так и с массивами.

Если вы тестируете с:

iterate_nested([[[1,2,3], [1,2,3]], [[1,2,3], [1,2,3]], [[1,2,3], [1,2,3]]]) do |key, item, depth|
  puts "Element: <#{depth.join('/')}/#{key}> = #{item}"
end

Это дает:

Element: <0/0/0/0> = 1
Element: <0/0/1/1> = 2
Element: <0/0/2/2> = 3
Element: <0/1/0/0> = 1
Element: <0/1/1/1> = 2
Element: <0/1/2/2> = 3
Element: <1/0/0/0> = 1
Element: <1/0/1/1> = 2
Element: <1/0/2/2> = 3
Element: <1/1/0/0> = 1
Element: <1/1/1/1> = 2
Element: <1/1/2/2> = 3
Element: <2/0/0/0> = 1
Element: <2/0/1/1> = 2
Element: <2/0/2/2> = 3
Element: <2/1/0/0> = 1
Element: <2/1/1/1> = 2
Element: <2/1/2/2> = 3

Cheerio!

0 голосов
/ 17 ноября 2009

Это действительно зависит от того, что вы пытаетесь сделать (далеко не достаточно информации в вопросе), но если вам нужно погрузиться на три или более уровней в Hash, вы вполне можете захотеть рекурсивный обход дерева алгоритм:

def hash_traverse(hash)
  result = ""
  for key, value in hash
    result << key.to_s + ":\n"
    if !value.kind_of?(Hash)
      result << "  " + value.to_s + "\n"
    else
      result << hash_traverse(value).gsub(/^/, "  ")
    end
  end
  return result
end

Вы уверены, что Hash - лучшая структура данных для того, что вы пытаетесь сделать?

0 голосов
/ 16 ноября 2009
h["cool"].keys

чтобы потом итерировать дерево было бы

h["cool"].keys.each |outer| { h["cool"][outer].each { |inner| puts inner }}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...