从地图构建已排序的部分

时间:2008-12-16 11:46:25

标签: ruby collections

我有未分类的键值对映射。

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

现在我想按键对它们进行排序,然后按键的第一个字符将它们分成几个部分。与此类似:

output1 = {
  "a" => {
      "aa" => "aavalue",
      "ab" => "abvalue",  
  },
  "b" => {
    "ba" => "bavalue",
  },  
  "x" => {
    "xa" => "xavalue",
  },  
}
  1. 虽然这是相对微不足道的,但我正在寻找一种简洁的方法来表达ruby中从输入到输出1的转换。 (我的方法可能比红宝石标准过于冗长)

  2. 您可能还注意到地图(通常)没有订购。因此,除非我手动对键进行排序并包含对地图的访问权限,否则上述数据结构将无法正常工作。那么如何在ruby中创建一个有序的有序映射?或者已经有一个?

  3. 如果有序地图方法不那么容易,我将不得不将最终结构更改为如下所示。我再次寻找一些简洁的ruby代码,从输入到输出2。

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

4 个答案:

答案 0 :(得分:2)

据我所知,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 :(得分:1)

我是一个pythonista,但我还是试过了:

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

答案 2 :(得分:1)

output = input.inject({}){ |h, p| k,v=p; (h[k[0..0]] ||= {})[k] = v; h}

答案 3 :(得分:1)

不幸的是,没有一个答案是完整的。所以我基于Thiago的解决方案想出了这个:

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
}