【问题标题】:building sorted sections from map从地图构建排序部分
【发布时间】:2008-12-16 11:46:24
【问题描述】:

我有未排序的键值对映射。

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

现在我想按键对它们进行排序,并按键的第一个字符将它们聚集成部分。类似这样:

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

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

  3. 如果有序映射方法不是那么容易,我将不得不将最终结构更改为如下所示。同样,我正在寻找一些从输入到输出的简洁 ruby​​ 代码。

.

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

【问题讨论】:

  • 有序的哈希只存在于 1.9 中,但是无序的可以变成数组。有时间我会在稍后发布解决方案

标签: ruby collections


【解决方案1】:

据我所知,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"}}]

使用类似的地图,您可以到达您列出的最后一个表格(输出2):

output2 = output.map { |pair|
  hash = pair.last
  { 'name' => pair.first,
    'keys' => hash.keys,
    'values' => hash.values }
}

【讨论】:

    【解决方案2】:

    我是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
    

    【讨论】:

    • c[first] = Hash.new unless c.has_key? first
    【解决方案3】:
    output = input.inject({}){ |h, p| k,v=p; (h[k[0..0]] ||= {})[k] = v; h}
    

    【讨论】:

    • 或者更简洁/隐秘:input.inject({}){|h, p| k,v=p; l=k[0..0]; h.merge(l => (h[l] || {}).merge(k => v))}
    • 来自 Bkkbrad 的那个较短 :) ...但都错过了订购部分。
    【解决方案4】:

    很遗憾,没有一个答案是完整的。所以我根据蒂亚戈的解决方案想出了这个:

    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
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-07-27
      • 2017-06-16
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-03-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多