построение отсортированных разделов с карты - PullRequest
2 голосов
/ 16 декабря 2008

У меня несортированная карта пар ключ-значение.

input = {
  "xa" => "xavalue",
  "ab" => "abvalue",
  "aa" => "aavalue",
  "ba" => "bavalue",
}

Теперь я хочу отсортировать их по ключу и сгруппировать их по разделам по первому символу ключа. Похоже на это:

output1 = {
  "a" => {
      "aa" => "aavalue",
      "ab" => "abvalue",  
  },
  "b" => {
    "ba" => "bavalue",
  },  
  "x" => {
    "xa" => "xavalue",
  },  
}
  1. Хотя это относительно тривиально, я ищу краткий способ выразить это преобразование из input в output1 в ruby. (Мой подход, вероятно, слишком многословен по отношению к рубиновым стандартам)

  2. Возможно, вы также заметили, что карты (как правило) не упорядочены. Таким образом, приведенная выше структура данных не будет работать должным образом, если я вручную не отсортирую ключи и не сверну доступ к карте. Итак, как мне создать ключевую упорядоченную карту в ruby? Или уже есть?

  3. Если подход с упорядоченной картой не так прост, мне пришлось бы изменить окончательную структуру на что-то вроде следующего. Снова я ищу какой-то лаконичный рубиновый код для ввода от ввода к выводу 2.

.

output2 = [
  {
    "name" => "a",
    "keys" => [ "aa", "ab" ],
    "values" => [ "aavalue", "abvalue" ],
  },
  {
    "name" => "b",
    "keys" => [ "ba" ],
    "values" => [ "bavalue" ],
  },
  {
    "name" => "x",
    "keys" => [ "xa" ],
    "values" => [ "xavalue" ],
  }
]

Ответы [ 4 ]

2 голосов
/ 16 декабря 2008

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

output = input.inject({}) { |acc, pair|
  letter = pair.first[0].chr
  acc[letter] ||= {}
  acc[letter][pair.first] = pair.last
  acc
}.sort

Это даст вам структуру данных в форме

[ ["a", {"aa"=>"aavalue",
         "ab"=>"abvalue"}],
  ["b", {"ba"=>"bavalue"}],
  ["x", {"xa"=>"xavalue"}]]

Путем отображения массивов компонентов в хэши ...

output.map {|pair| {pair.first => pair.last}}

Вы можете превратить его во что-то вроде

[{"a"=>{"aa"=>"aavalue",
        "ab"=>"abvalue"}},
 {"b"=>{"ba"=>"bavalue"}},
 {"x"=>{"xa"=>"xavalue"}}]

Имея похожую карту, вы можете перейти к последней указанной вами форме (output2):

output2 = output.map { |pair|
  hash = pair.last
  { 'name' => pair.first,
    'keys' => hash.keys,
    'values' => hash.values }
}
1 голос
/ 03 января 2009

К сожалению, ни один из ответов не был полным. Поэтому я придумал это на основе решения Тиаго:

output1 = input.inject({}) { |acc, pair|
  letter = pair.first[0].chr
  acc[letter] ||= {}
  acc[letter][pair.first] = pair.last
  acc
}.sort

output2 = output1.inject([]) { |acc, pair|
  acc << {
    'name' => pair.first,
    'keys' => pair.last.keys(),
    'values' => pair.last.values()
  }
  acc
}
1 голос
/ 16 декабря 2008
output = input.inject({}){ |h, p| k,v=p; (h[k[0..0]] ||= {})[k] = v; h}
1 голос
/ 16 декабря 2008

Я питонист, но я все равно попробовал:

class Hash
  def clustered
    clustered = Hash.new
    sort.each do | key, value |
      first = key[0,1]
      unless clustered.has_key?(first)
        clustered[first] = Hash.new        
      end
      clustered[first][key] = value
    end
    clustered
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...