Hash
在其他语言称为Object
, Dictionary
,但无论是在哪个程序语言中,Hash
和 Array
都为组成资料中两个很重要的元素。许多资料结构为不单单只是阵列,也不单单只是Hash,甚至有很多复杂的Hash
搭配Array
的结构等等。
今天,我们会仔细的介绍Array
跟 Hash
之间的关系
论阵列转Hash
,最简单的方式就是先把资料型态为凑为俩俩一对,之後再to_h
便很容易
[%w(a b), %w(c d), %w(e f)].to_h #=> {"a"=>"b", "c"=>"d", "e"=>"f"}
%w(a b c d e f).to_h #=> 会坏掉
将上述的观念建立起来以後,我们来开始看其他转 Hash
的情境
虽然我们不能写成 %w(item1 item2 item3 item4).to_h
,但我们可以使用下列的方式转为hash
a = ["item 1", "item 2", "item 3", "item 4"]
h = Hash[*a]
#=> { "item 1" => "item 2", "item 3" => "item 4" }
#zip
作配对以後,转为杂凑不仅想要将两个阵列凑成Hash
,还希望当中的key
为符号的话,我们该怎麽做?以下提供三种转Hash
的方法。
keys = %w[a b c d e]
values = %w(apple bear cat dog elephant)
Hash[keys.map(&:to_sym).zip(values)]
#=> {:a=>"apple", :b=>"bear", :c=>"cat", :d=>"dog", :e=>"elephant"}
# Ruby 2.1.0 以上可以用
keys.zip(values).to_h
keys.map(&:to_sym).zip(values).to_h
# Ruby 2.5 以上可以用 transform_keys
Hash[keys.zip(values)].transform_keys { |k| k.to_sym }
Day4 讲过,当我们要转换为比较复杂的资料型态如hash
, array
的话,比起使用inject
, reduce
,使用each_with_object
会比较简洁。
下列提供inject
, each_with_object
两种方法比对,虽然Day4已经提过,但还是要强调两者之间的accumulator
位置不一样。inject
在前面,而each_with_object
在後面
#======= 情境1: 使用inject
[:foo, :bar, :jazz].inject({}) do |hash, item|
hash[item] = item.to_s.upcase
hash
end
#=> {:foo=>"FOO", :bar=>"BAR", :jazz=>"JAZZ"}
#======= 情境1: 使用each_with_object
[:foo, :bar, :jazz].each_with_object({}) { |item, hash| hash[item] = item.to_s.upcase }
#=> {:foo=>"FOO", :bar=>"BAR", :jazz=>"JAZZ"}
#======= 情境2: 使用inject
array = [['A', 'a'], ['B', 'b'], ['C', 'c']]
array.inject({}) do |memo, values|
memo[values.first] = values.last
memo
end
# => {'A' => 'a', 'B' => 'b', 'C' => 'c'}
#======= 情境2: 使用each_with_object
array = [['A', 'a'], ['B', 'b'], ['C', 'c']]
array.each_with_object({}) do |values, memo|
memo[values.first] = values.last
end
# => {'A' => 'a', 'B' => 'b', 'C' => 'c'}
Hash
转为 Array
处理的话相对单纯,Hash
只要to_a
就会转为Array
Invoice.statuses.to_a
#=> [["unissued", 0], ["issued", 1], ["allowance", 2], ["allowance_failed", 3]]
我们也可以使用each_with_object
将原本为Hash
的资料转为型态更复杂的Hash
#======= 情境1
t = {0=> "a", 1=> "b", 5=> "c"}
t.each_with_object([]) {|(k,v), a| a[k]=v}
#=> ["a", "b", nil, nil, nil, "c"]
#======= 情境2: 转为array of object
{ foo: 1, bar: 2, jazz: 3 }.each_with_object([]) do |(key, value), array|
array << { id: value, name: key }
end
# => [{:id=>1, :name=>:foo}, {:id=>2, :name=>:bar}, {:id=>3, :name=>:jazz}]
⭐️ each_with_object
里头只能放阵列与杂凑等可以扩充的容器,若把each_with_object
当作inject
使用的话,则会出现凄惨情况。
(1..5).each_with_object(1) { |value, accu| value + accu } #=> 1 (不是15)
⭐️ 使用rails enum helper
,搭配下拉式选单,我们可以用以下方式将Hash 转为阵列
class Order < ApplicationRecord
# 情境1. module in class
module Status
UNPAID = :unpaid # 未付款
PROCESSING = :processing # 处理中
WAITING = :waiting # 已出货
DONE = :done # 已完成
CANCELED = :canceled # 已取消
RETURNED = :returned # 退货/退款
end
# 情境2. enum
enum shipping_type: {
home: 0, # 宅配
cvs: 1 # OK/莱尔富/全家
}
end
通常要使用enum helper
转阵列的情境,都是在要将enum
转换为前端下拉式选单的资料结构用。
module Admin::OrdersHelper
#=> [["所有订单状态", nil], ["退货/退款", :returned], ["未付款", :unpaid],
# ["处理中", :processing], ["已完成", :done], ["已出货", :waiting], ["已取消", :canceled]]
def order_status
Order::Status.constants
.map { |c| Order::Status.const_get(c) }
.map { |k| [t("orders.status.#{k}"), k] }
.prepend ['所有订单状态', nil]
end
#=> [['所有配送方式', nil], ["宅配", "home"], ["超商取货", "cvs"]]
def order_shipping_type(prepend: true)
options = Order.shipping_types.map { |k, v| [t("orders.shipping_type.#{k}"), k] }
# radio-button
return options unless prepend
# 下拉式选单
options.prepend ['所有配送方式', nil]
end
end
今天介绍了Array
, Hash
之间转换的关系,明天让大家瞧瞧Ruby
的时间魔术师。
>>: 从 IT 技术面细说 Search Console 的 27 组数字 KPI (6) :网页
最近两篇都是讲 navigation component,入面为了示范设定 navigation 我...
引言 昨天介绍了套件管理软件以及图形化使用者界面的安装,也是指令介绍的最後一篇文章。学习了这麽多指令...
单执行绪 JavaScript 是单执行绪的语言,而单执行绪的意思就是一次只做一件事情。 不过这样的...
前言: 几个基本的页面都设计得差不多啦~这次的挑战也快接近尾声了!今天就让阿森来介绍一个有点小特效...
格式化输出 使用%字元,基本的格式为: Print(“ %输出格式 ” % (变数1,变数2……)...