> s = "a=1, b=2, c=3, d=4"
=> "a=1, b=2, c=3, d=4"
> Hash[s.split(",").map(&:strip).map { |p| p.split("=") }.map { |k, v| [ k.to_sym, v.to_i ] }]
=> {:a=>1, :b=>2, :c=>3, :d=>4}
问题的一部分在于您试图在单行中完成它,并失去了对中间值的跟踪。将其拆分为每个组件,确保使用 Ruby 给您的内容等。
您的命名假设您会收到一个数组(而不是哈希表)。Hash[...]将基于
[key, value]
对的数组创建哈希表。这样可以避免手动填充哈希表。此外,该方法应返回哈希表而不是设置某些内容-保持方法小且纯净。
请注意,我修剪了第一组分割值。这样可以避免像
:" a"
这样的符号,如果不修剪前导/尾随空格,则会出现这种情况。我的代码没有考虑类似
"a = 1"
的字符串-您的代码应该考虑。
首先,使事情可读。然后,如果(仅当)它有意义并且仍然易读时,请进行代码压缩。
> s = "a=1, b=2, c=3, d=4"
=> "a=1, b=2, c=3, d=4"
> a1 = s.split(",")
=> ["a=1", " b=2", " c=3", " d=4"]
> a2 = a1.map(&:strip)
=> ["a=1", "b=2", "c=3", "d=4"]
> a3 = a2.map { |s| s.split("=") }
=> [["a", "1"], ["b", "2"], ["c", "3"], ["d", "4"]]
> a4 = a3.map { |k, v| [ k.to_sym, v.to_i ] }
=> [[:a, 1], [:b, 2], [:c, 3], [:d, 4]]
> Hash[a4]
=> {:a=>1, :b=>2, :c=>3, :d=>4}
虽然与下面要翻译的内容无关,但如果你在使用Ruby进行大量ETL(抽取、转换和加载)操作,尤其是对纯文本进行操作,使用mixins可以使代码更加清晰,接近DSL(领域特定语言)。你也可以玩一些奇怪的游戏,比如:
> def splitter(sym, s)
String.send(:define_method, sym) do
split(s).map(&:strip)
end
end
> s = "a=1, b=2, c=3, d=4"
> splitter :split_comma, ","
> splitter :split_eq, "-"
> Hash[s.split_comma.map(&:split_eq).map { |k, v| [ k.to_sym, v.to_i ]}]
=> {:a=>1, :b=>2, :c=>3, :d=>4}
它可以变得比这更糟,成为一个完整的ETL DSL。如果需要,这是非常好的。
scan
函数几乎肯定是更好的选择,而且更加健壮。 - Dave Newtonv.to_i
,虽然如果我要这样做,我会避免使用tapping
,而只是使用string.scan(/(\w)=(\d)/).each_with_object({}){|(k,v),obj| obj[k.to_sym] = v.to_i}
将其添加到我的帖子中。 - engineersmnky