想先说明以下观念。
2.7.3 :081 > 1 + 1
=> 2
# + 在这里是数字类别的方法
2.7.3 :082 > "1" + "1"
=> "11"
# + 在这里是字串类别的方法
1 + "1"
或"1" + 1
会喷TypeError错误,是因为两种类别的 + 方法,规定了所能运用的资料型态。而不是+方法自己规定了两种资料型态不能相加。
自己动手做一个同名但不同类别都有的方法。
class A_class
def super_method
puts "我是A方法"
end
end
=> :super_method
class B_class
def super_method
puts "我是B方法"
end
end
=> :super_method
2.7.3 :096 > a = A_class.new
=> #<A_class:0x00007fcb083dbcf8>
2.7.3 :097 > a.super_method
我是A方法
=> nil
2.7.3 :098 > b = B_class.new
=> #<B_class:0x00007fcb083aa978>
2.7.3 :099 > b.super_method
我是B方法
=> nil
为何提这个是因为,类别里常有"同名"的方法,在学习初期,我们常常会记Array也可以相加,但事实上是阵列也有自己的+
的方法。
2.7.3 :100 > [1, 2, 3] + [1, 2, 3]
=> [1, 2, 3, 1, 2, 3]
duck typing
请不要把下面文章想成原理,想成是一个故事。
Ruby是鸭子型别的设计风格。
「当看到一只鸟走起来像鸭子、游泳起来像鸭子、叫起来也像鸭子,那麽这只鸟就可以被称为鸭子。」
我们把一开始的同名方法整理一下。
class Dog
def has_a_method
puts "我会叫,我会跑,我会游泳"
end
end
class Cat
def has_a_method
puts "我会叫,我会跑,我会游泳"
end
end
class Duck_look_like
def yes_i_can(another_animal)
another_animal.has_a_method
end
end
2.7.3 :252 > kind_of_animal = Duck_look_like.new
=> #<Duck_look_like:0x00007fa17b39dd10>
2.7.3 :253 > kitty = Dog.new
=> #<Dog:0x00007fa17b3265a8> #有一只kitty
2.7.3 :254 > lucky = Cat.new
=> #<Cat:0x00007fa17b417c78> #有一只lucky
#这边故意反惯例,表示不在意他们本质。
2.7.3 :255 > kind_of_animal.yes_i_can(kitty)
我会叫,我会跑,我会游泳
=> nil
2.7.3 :256 > kind_of_animal.yes_i_can(lucky)
我会叫,我会跑,我会游泳
=> nil
我在做的不是规定鸭子是什麽,而是让狗与猫变成像鸭子一样。
初学时会说,那这一切都是设计好的呀?
无论有人说这种设计让Ruby好学或是难学,好维护或难维护,但这种设计是为了我们能更快速操作"物件"。
关於duck typing
还会有其他衍生的问题,例如Monkey Patch
等,也是很好的讨论问题,这边稍微提到是因为明天会分享一些转换类型的leetcode题型做分享。
能解决问题就是好魔法。
用"",与''包起来的任何字元都为字串。
2.7.3 :015 > "234234*(&%*(X34234.".class
=> String
2.7.3 :016 > '1+1=2'.class
=> String
2.7.3 :010 > "".class
=> String
2.7.3 :011 > ''.class
=> String
#即使""里面是nil,也是字串。
我们来让字串像其他类别吧。
2.7.3 :021 > "str" + "str"
=> "strstr"
2.7.3 :022 > "str"*8
=> "strstrstrstrstrstrstrstr"
2.7.3 :020 > str = String.new
=> ""
2.7.3 :023 > str << "123"
=> "123"
2.7.3 :024 > str << "456"
=> "123456"
2.7.3 :025 > "abc".bytes
=> [97, 98, 99]
#当然不只这些。
分享过的:leetcode.028:Implement strStr()
解法为利用index方法,由於已写过就不重复拿来骗篇幅,直接整理如下。
def str_str(haystack, needle)
ans = haystack.index(needle)
ans != nil ? ans : -1
end
def str_str(haystack, needle)
haystack.index(needle) != nil ? haystack.index(needle) : -1
end
#看久了三元运算子很可爱,不常看觉得很讨厌,跟不准家里养宠物的爸妈,看到偷抱回来的毛小孩一样。
阵列由於记忆体储存方式,常会是用到回圈,迭代,枚举的好题型。
2.7.3 :026 > arr = Array.new
=> []
2.7.3 :027 > arr << 1
=> [1]
2.7.3 :028 > arr << 2
=> [1, 2]
2.7.3 :029 > arr << "3"
=> [1, 2, "3"]
# << 这个方法,阵列与字串的非常的不同。
#另外阵列也可以运用到运算符号,但使用结果与使用对象须注意
2.7.3 :031 > [1, 2, "3", 1, 2, "3"] - [1, 2, "3"]
=> []
2.7.3 :032 > [1, 1, 1] + [1, 2, 3]
=> [1, 1, 1, 1, 2, 3]
2.7.3 :033 > [1] * [1]
TypeError (no implicit conversion of Array into Integer)
2.7.3 :034 > [1] * 5
=> [1, 1, 1, 1, 1]
leetcode035:Search Insert Position
跟上题连结一样。
#先不简化
def search_insert(nums, target)
nums.each_with_index do |num, index|
if num >= target
return index
end #大於0的目标与里面的值的关系是,刚好相等时回报位置,比较小时取代里面值的位置
end
nums.size
end
def search_insert(nums, target)
nums.each_with_index do |num, index|
return index if num >= target
end
nums.size
end
Range用到new时,需要带入正确参数,所以在解题上常会直接写出自己要的范围,不常会用到new。
2.7.3 :036 > Range.new
ArgumentError (wrong number of arguments (given 0, expected 2..3))
#也不是随便带参数就可以。
2.7.3 :045 > Range.new(1, 6)
=> 1..6
2.7.3 :046 > Range.new("a", 6)
ArgumentError (bad value for range)
2.7.3 :047 > Range.new("a", "b")
=> "a".."b"
#字串可以的原因,字母本身具有自己的字节数。
2.7.3 :007 > "a".bytes
=> [97]
2.7.3 :008 > "z".bytes
=> [122]
#很好玩的一点
2.7.3 :037 > 1..6.class
ArgumentError (bad value for range)
#字串,数字,阵列,杂凑我们自己输入好就会new完成。范围没有。
2.7.3 :038 > (1..6).class
=> Range
一般解题刚接触范围,常见到会用在回圈,例如:
for num in 1..array.size-1 do ... end
#或是..与...差异
2.7.3 :040 > (1..5).to_a
=> [1, 2, 3, 4, 5]
2.7.3 :041 > (1...5).to_a
=> [1, 2, 3, 4]
#另外不用to_a转型写法。
2.7.3 :043 > [*"a".."h"]
=> ["a", "b", "c", "d", "e", "f", "g", "h"]
leetcode.122:Best Time to Buy and Sell Stock II
#第一个是错误答案,第二个正确,主要是因为..与...差异。
def max_profit(prices)
max_profit = 0
for i in 0..(prices.size - 1)
max_profit += (prices[i+1] - prices[i]) if prices[i+1] > prices[i]
end
max_profit
end
def max_profit(prices)
max_profit = 0
for i in 0...(prices.size - 1)
max_profit += (prices[i+1] - prices[i]) if prices[i+1] > prices[i]
#prices[i+1] > prices[i] && max_profit += (prices[i+1] - prices[i])
# 上一句可改写成这样,久了会习惯,不习惯就是原本的比较好。
end
max_profit
end
习惯多利用each,map
def max_profit(prices)
max_profit = 0
prices.each_cons(2) do |price , next_price|
next_price > price && max_profit += next_price - price
end
max_profit
end
後面日程会再提到each,map。
若真有比我新的新手路过,先记得初期题型Range比较常被拿来利用,尤其在阵列身上。
又爱又恨...
原因是ㄓ跟ㄗ,ㄔ跟ㄘ
先了解长相
2.7.3 :050 > {a: 123, :b => 123}.class
=> Hash
#前面是比较新的写法,後面是箭头式,都对。
2.7.3 :051 >{a: 123, :a => 123}.class
(irb):51: warning: key :a is duplicated and overwritten on line 51
=> Hash
#被覆盖指向了,所以请确定Key没用过。
2.7.3 :052 > {a: 123, "a": 123}.class
(irb):52: warning: key :a is duplicated and overwritten on line 52
=> Hash
#一样被overwritten
2.7.3 :054 > {:a => 123, "a" => 123}.class
=> Hash
#又没问题了....
会这样的原因在昨日的符号。
新手初期手动写杂凑请记得格式统一。
利用运算变成Hash的资料也是帮你统一格式,没理由自己写用两种以上格式。
Hash在学习上除了知道找Key跟Value怎麽处理外,会有很多题型是将资料转成Hash来处理。
2.7.3 :057 > hash = { a: 1, b: 2, c: 3}
=> {:a=>1, :b=>2, :c=>3}
2.7.3 :058 > hash.keys
=> [:a, :b, :c]
2.7.3 :059 > hash.values
=> [1, 2, 3]
#keys与values这两个用复数,这惯例在Rails上也很常见,可以当成一种习惯。
2.7.3 :060 > hash[:a]
=> 1
2.7.3 :061 > hash[:b]
=> 2
2.7.3 :063 > hash.index(2)
=> :b
leetcode001:two_sum
永远劝退的第一题
def two_sum(nums, target)
new_hash = {}
nums.each_with_index do |num, index|
return [new_hash[num], index] if new_hash.has_key?(num)
new_hash[target - num] = index
end
end
def two_sum(numbers, target)
hash = {}
numbers.each_with_index do |num, i|
return [hash[target - num] +1 , i + 1] if hash[target - num]
hash[num] = i
end
end
#说明,文章连结都有喔。
利用枚举产生的Hash,其中的Key与Value常是会有关联性的,依照这个关联性,当我们知道其中一个值後,能很快速知道另外一个的结果。
例如
2.7.3 :075 > [1, 2, 3, 3, 5, 6, 1, 2, 7].group_by {|num|num}
=> {1=>[1, 1], 2=>[2, 2], 3=>[3, 3], 5=>[5], 6=>[6], 7=>[7]}
2.7.3 :076 > [1, 2, 3, 3, 5, 6, 1, 2, 7].tally
=> {1=>2, 2=>2, 3=>2, 5=>1, 6=>1, 7=>1}
查表法难在建立表格,建好之後的快乐会让你忘记建立时的痛苦。
Hash往往是被介绍的很少,但後面越用用多的资料类型,尤其到Rails後,可以发现所有实体都长的跟Hash没什麽差别,刷题与学习Rails不一定有正比关系,但是练习越多,越不会害怕Hash,越能体会迭代与枚举的好处。
今日提到的。
1.Duck Typing
2.一些曾经解过的leetcode题目。
>>: Day 02 :zsh 与 shell script
本质上是一样的东西,只是一个是在 request 前执行、一个是在收到 response 後执行,分...
上一次有提到说,修改 commit 的方式有以下几种: 把 .git 目录整个删除,暴力破解法,请不...
今天进度 : 鸟哥私房菜 - 第十九章、主机名称控制者: DNS 服务器 今天使用 whois 指令...
看完永丰的API规格书,开始盘点所需之参数。 由规格书可知,呼叫API所需要的参数有Version、...
IEHistoryView 今天来认识 IEHistoryView 虽然 IE 已经停止更新很久了,...