Ruby Study 4 : Array

简介:
Array class
1. introduce
Ruby的Array类和其他的不太一样, Ruby中允许一个Array对象中存储不同类型的元素. 例如 :
class Myclass
end
my1 = Myclass.new
a1 = Array.new([1,"Digoal",[1,2,3,4,5],4,my1])
p a1

执行结果 : 
[1, "Digoal", [1, 2, 3, 4, 5], 4, #<Myclass:0x1e11250>]

与String类类似, 也可以使用index来访问Array对象中的元素, index从0 开始 :
# 接上面的代码
puts(a1[0])
puts(a1[1])

输出 : 
1
Digoal

还可以把操作系统命令输出的结果存储到Array对象中, 如 :
a1 = %W/a b c d #{`dir`}/

还有一种更有意思的类叫Dir, 可以把指定文件夹下的文件和目录名转成Array对象.
#!/opt/ruby/bin/ruby
p(Dir.entries('/'))  # 这种用法是调用的class的singleton method, 我们可以通过Dir.singleton_methods来查看它有哪些singleton methods
print(Dir.singleton_methods)  # 结果为Symbol对象, 其中就有entries.

执行结果 :
["home", "opt", "tmp", "net", "proc", "bin", "dev", "etc", "pgxc_gtm", ".autorelabel", "..", "pgdata", "lib", "mnt", "pgdata1919", "boot", "root", ".autofsck", "misc", "srv", "usr", "selinux", ".", "var", "lost+found", "hds2", "lib64", "sys", "sbin", "media", "hds1"]
[:open, :foreach, :entries, :chdir, :getwd, :pwd, :chroot, :mkdir, :rmdir, :delete, :unlink, :home, :glob, :[], :exist?, :exists?]


2. create a new Array object
创建一个Array对象, 方法比较多 :
a1 = ['a','b',1,2]
a2 = %W/a b c 1 2 3 4 5 #{1+2}/
a3 = %w/a b c d e d f #{1+2}/
a4 = Array.new([1,2,'a'])  
a5 = Array.new(3,"abc")  # 创建含有3个元素的Array对象, 元素都是"abc"
print(a1.class, a2.class, a3.class, a4.class, a5.class, "\n")  # 通过以上方法创建的都是Array 对象.
p(a1)
p(a2)
p(a3)
p(a4)
p(a5)

执行结果 : 
ArrayArrayArrayArrayArray
["a", "b", 1, 2]
["a", "b", "c", "1", "2", "3", "4", "5", "3"]
["a", "b", "c", "d", "e", "d", "f", "\#{1+2}"]
[1, 2, "a"]
["abc", "abc", "abc"]


3. nil
当访问一个Array类的index不存在这个元素时, 返回的是nil.
我们来看个例子 :
a1 = %W/a b c d/
puts( a1[4].inspect )
puts( a1[4].class )  # nil属于NilClass
puts( a1[4] ) # 1.8中显示nil, 1.9中显示为空. 所以在1.9中可使用p 或inspect来显示nil.
puts( a1[4].nil? )  # nil? 方法可以用来判断这个对象是否为nil.

结果 : 
nil
NilClass

true


4. multidimensional Arrays
多维Array, 有几种创建方法 :
a1 = Array.new(2)
a1[0] = [1,2,3,4]  # 赋予对应的index的值.
a1[1] = [5,6,7,8]
puts(a1.inspect)

输出结果 : 
[[1, 2, 3, 4], [5, 6, 7, 8]]

还可以直接来创建 :
a1 = [[1,2,3,4],
      [5,6,7,8]]  # 换行是没有必要的, 这里这么写看起来比较舒服一点而已. 也可以写成 a1 = [ [1,2,3,4], [5,6,7,8] ]

注意在使用Array.new创建Array对象时, 如果传入了初始值, 并且没有使用括弧的话, 必须在new后加上空格, 如下 : 
a1 = Array.new [1,2,3,4]
a2 = Array.new([1,2,3,4])
a3 = Array.new[1,2,3,4]  # 这句的写法就有问题.

5. Iterating over Array
前面几篇BLOG我已经讲过很多Iterating的例子, 比如说Range对象, 可以用在for 或者调用each方法等进行Iterat操作. Array同样适用.
a1 = [1,2,3,4]
a1.each {
  |x|
  puts(x*x)
}

执行结果 :
1
4
9
16

或者使用 for循环.
a1 = [1,2,3,4]
for x in a1 do
  puts(x*x)
end

执行结果 :
1
4
9
16

当嵌套Array时, 可以传递多个变量给for循环.
a1 = [ [1,2,3,4],
       [5,6,7,8],
       [9,10,11,12]
     ]

for (a,b,c,d) in a1 do
  puts("a:#{a}, b:#{b}, c:#{c}, d:#{d}.")
end

执行结果 :
a:1, b:2, c:3, d:4.
a:5, b:6, c:7, d:8.
a:9, b:10, c:11, d:12.

还可以这样写 : 
a1 = [ [1,2,3,4],
       [5,6,7,8],
       [9,10,11,12]
     ]

for x in a1[0] do
  puts(x)
end

puts(a1[0].class)  # 因为a1[0] 还是Array类对象.

执行结果 :

1
2
3
4
Array


6. Indexing into Array
在第一点里面已经讲过了index. 这里再展开一下, 看个例子 :
arr = ['h','e','l','l','o',' ','w','o','r','l','d']
p( arr[0,5] )  # 从0开始, 取5个元素
p( arr[-5,5 ] )  #  从-5开始取5个元素.
p( arr[0..4] )  # 取0,1,2,3,4 元素
p( arr[-5..-1] )  # 取-5,-4,-3,-2,-1 元素

执行结果 : 
["h", "e", "l", "l", "o"]
["w", "o", "r", "l", "d"]
["h", "e", "l", "l", "o"]
["w", "o", "r", "l", "d"]

通过index新增或修改对应元素的值, 如果从后面写入了一个较大index的元素, 中间可能出现nil的值. 例如 :
a1 = [1,2,3,4,5]
a1[10] = "ok"  # 5,6,7,8,9 index 都将用nil填充
p a1

结果 :
[1, 2, 3, 4, 5, nil, nil, nil, nil, nil, "ok"]

使用index对元素进行范围修改,
a1 = [1,2,3,4,5]
a1[0..2] = 1  # 注意这个不是要把0,1,2三个元素分别改成1. 而是三个元素变一个了.
p a1
p a1.length # 改完长度变3了.
a1[0,2] = 2,3   #这里是要把a1[0], a1[1]的值改成2 , 3 .也可以写成 a1[0,2] = [2,3]
p a1

执行结果 :
[1, 4, 5]
3
[2, 3, 5]

7. Copy Array
与String类似, 拷贝Array和赋值是两码事. 需要分清楚.
a1 = %W/i am digoal/
a2 = a1
a3 = a1.clone()  #  这个是拷贝一个与a1值相同的array给a3. 所以object_id是和a1,a2不一样的.
puts(a1.object_id)
puts(a2.object_id)
puts(a3.object_id)

执行结果 :
16286088
16286088
16286076

8. Testing Array for Equality
Array对象中有一个方法 <=> 用来比较两个Array. 
结果 -1, 0, 1
a1 = %W/a b c d/
a2 = %W/a a a a a/
print(a1.methods.include?(:<=>),"\n")  # 判断是否存在<=>方法, 当然是true的.
puts(a1 <=> a2)  # 左边的array大于右边的, 默认是ASCII码, 逐个比较.
puts(a1.length <=> a2.length)  # 比较长度, 右边的大于左边的. 实际这个时候用的是Fixnum 的<=>方法. 而不是Array的<=>方法
a2 = a1
puts(a1 <=> a2)  # 左边等于右边, 返回0
puts(a1.length.class)  # 返回Fixnum

执行结果 :
true
1
-1
0
Fixnum

后面还会讲到, 一些Array之间进行比较的操作实际上调用的是<=>方法, 来判断大小的.
另外需要注意的是, <=>方法, 当两个进行比较的Array中的元素类型不一致时, 返回的是nil.
p(["2",2,3] <=> ["1","2","3"])  # 这里虽然两个Array的后面两个元素类型不一致, 但是在第一个元素进行比较时已经知道大小了, 所以不会比较后两个元素.
p(["1",2,3] <=> ["1","2","3"])  # 这里就不一样了因为第一个元素相等, 还需要比较第二个元素, 这时两个Array的第二个元素类型不一致, 返回nil

执行结果 :

1
nil


9. Sorting Arrays
Array元素排序, 值得注意的是, Array内的元素类型必须一致, 元素内不能包含nil.
否则会报错, 当然有办法解决 :
a1 = ["a",1,2,3,nil,nil,4,5,6,"b"]
a1.sort

报错 : 
comparison of String with nil failed (ArgumentError)

类型不一致 : 报错
a1 = ["a",1,2,3]
a1.sort
# comparison of String with 2 failed

解决办法, 给sort输入一个block , 这个块中有两个变量,a,b 分别代表Array中的连续的两个元素 :
a1 = ["a",1,2,3,nil,nil,"b"]
p a1.sort {
  |a,b|
  a.to_s <=> b.to_s
}

结果 : 
[nil, nil, 1, 2, 3, "a", "b"]


10. Comparing Arrays
比较操作符为> , < , ==.
比较其实就是调用了<=>方法, 只是返回true, false, 而不是-1, 0, 1 .
<=> 方法来自Comparable模块.
但是使用比较操作符必须包含Comparable模块. 接下来例子 :
a1 = [2,1,2,3,nil,nil,"b"]
a2 = [1,2,3,4,5,6,7,8,9,0]

a1 > a2

报错 : 
undefined method `>' for [2, 1, 2, 3, nil, nil, "b"]:Array (NoMethodError)

修正 :
include Comparable
a1 = [2,1,2,3,nil,nil,"b"]
a2 = [1,2,3,4,5,6,7,8,9,0]

puts(a1 > a2)

结果 : 
true

当然每次都要include Comparable很烦, 可以给Array增加这个, 或者写一个自己的Array类. 如下 :
class Array
include Comparable
end
a1 = [2,1,2,3,nil,nil,"b"]
a2 = [1,2,3,4,5,6,7,8,9,0]

puts(a1 > a2)

或者
class Myarray < Array
include Comparable
end
a1 = Myarray.new([2,1,2,3,nil,nil,"b"])
a2 = Myarray.new([1,2,3,4,5,6,7,8,9,0])

puts(a1 > a2)

另外, 如果你不想比较ASCII值, 而是想比较Array的长度的话, 还可以复写<=>方法.
class Myarray < Array
include Comparable
def <=> (anotherary)
  self.length <=> anotherary.length
end
end
a1 = Myarray.new([2,1,2,3,nil,nil,"b"])
a2 = Myarray.new([1,2,3,4,5,6,7,8,9,0])

puts(a1 > a2)
返回
false

或者 :
class Array
include Comparable
def <=> (anotherary)
  self.length <=> anotherary.length
end
end
a1 = [2,1,2,3,nil,nil,"b"]
a2 = [1,2,3,4,5,6,7,8,9,0]

puts(a1 > a2)
返回
false


11. Array Methods
举一些例子, 你可以用Array对象的methods方法看.
&     Returns common elements of two arrays, no duplicates
+     Returns array concatenating two arrays
-     Returns array with items in second array removed from first
<<       Modifies first array by appending items from second array
clear    Modifies array by removing all elements
compact      Returns array with nil items removed
compact!      Modifies array by removing nil items
delete( object )     Modifies array by deleting object
delete_at( index )     Modifies array by deleting item at index
flatten         Unpacks nested array items and returns array
flatten!         Modifies array by unpacking nested array items
length          Returns number of elements in array
reverse          Returns array with elements in reverse order
reverse!         Modifies array by reversing element order
sort           Returns array sorted using <=>
sort!            Modifies array sorted using <=>

例子 : 
arr1 = [1,1,2,2,3,3]
arr2 = [1,2,3,4,5,6,7,8,9]
arr3 = ['h','e','l','l','o',' ',nil,'w','o','r','l','d']
p(arr1&arr2 )    #=> [1, 2, 3]  有去重的效果
p(arr1+arr2)        #=> [1, 1, 2, 2, 3, 3, 1, 2, 3, 4, 5, 6, 7, 8, 9]
p(arr1-arr2)        #=> []  对排除在外的元素有去重的效果
p(arr2-arr1)        #=> [4, 5, 6, 7, 8, 9]
arr1<<arr2     # 会修改左边的对象的原始值
p(arr1)        #=> [1, 1, 2, 2, 3, 3, [1, 2, 3, 4, 5, 6, 7, 8, 9]]  这里需要注意<< 加进来后是一个元素, 不是分解后的多个元素.
arr1.clear    # 会修改左边的对象的原始值
p(arr1)        #=>[]

12. Appending vs Concatenating
这里特别要讲一下append和concate .
也就是 + 和 <<
+ 不改变原始值, <<改变原始值.
+ 是把右边的Array对象按元素一个个加进来,
<< 是把右边的Array当成一个元素加进来.

【参考】
The Book Of Ruby
Ruby 1.9.3 API


目录
相关文章
|
7月前
|
Ruby
|
7月前
|
Ruby 索引
|
7月前
|
存储 Java Ruby
|
索引 Ruby
【Ruby on Rails全栈课程】2.6 ruby的数据结构--数组(Array)
数组是一个集合,但是不仅仅是数字的集合,可以是任何对象(String、 Integer、 Fixnum、 Hash、 Symbol 等对象)的集合。数组的索引是从0开始的有序整数,可以通过正数索引或者负数索引来寻找数组中的值,数组中的值是有顺序的。
95 0
|
移动开发 关系型数据库 Ruby
|
iOS开发
IOS 7 Study - Manipulating a Navigation Controller’s Array of View
ProblemYou would like to directly manipulate the array of view controllers associated with aspecific navigation controller SolutionUse the viewContro...
734 0
|
Ruby
Ruby Scripting - Array
A literal array is created by putting squarebrackets around a comma-separated list of elements eg: # ["zero" , "un" , "dos" , "tre" ] a = ['zero' , 'un' , 'dos' , 'tre' ] # 4 a.
655 0