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

时间: 2024-09-13 12:41:08

Ruby Study 4 : Array的相关文章

Ruby Study 10 : Exception Handling

exception 在程序开发中是不可或缺的部分, 程序在使用过程中总会遇到不可预知的问题, 例如可预知的访问文件的程序可能在访问过程中文件被删除或移动等. 但是总会有不可预知的, 不可能在写程序时全部规避掉. 所以就有了exception handling. 在Ruby中exception 是Exception calss或者它的subclass的object. 下面来详细的讲解一下异常时如何捕获exception. 注意Ruby的Exception Handling分为几个层面 , 异常执行

Ruby Study 3 : String and Range class

1. Normal String Delimiter ( ' and " ) 前面两篇已经接触了很多String的例子, 下面再举一个, 注意看单引号和双引号的区别 : s1 = 'Hello' s2 = 'World' s3 = '#{s1} #{s2}' s4 = "#{s1} #{s2}" puts(s3) puts(s4) 执行结果 : #{s1} #{s2} Hello World 2. User Defined String Delimiter 当String中有

Ruby Study 8 : Methods

1. Class Methods 调用一个方法时, 可以通过定义这个方法的类的对象来调用, 那么这个称为实例方法. 还可以定义类方法, 这种方法的调用需要通过类来调用, 不能通过这个类的对象来调用. 其实我们创建的Class也是一个对象, 这个后面会讲到, 所以方法都是由对象来调用的. class MyClass def MyClass.classMethod # 定义class method可以使用这种写法, 后面还会介绍其他写法.class method也称为这个class的singleto

Ruby Study 12 : Symbols

本章主要讲解Symbol 类. 讲解Symbol比较重要的是大家需要了解object_id的知识. Symbol和Fixnum很相似, 同样的symbol它们的object_id是一致的, 而字符串则不是这样的, 举个例子来回忆一下: v1 = :name p v1 p v1.object_id p :name.object_id v2 = "name" p v2 p v2.object_id p "name".object_id v3 = 10 p v3 p v3

Ruby Study 6 : Loops and Iterators

前面多次介绍到了Array, Hash, Set, Range, Matrix, Vector 等collection class的Iterator特性, 如each方法. 这次专门讲一讲Loops和Iterators. 1. for loops for循环和其他编程语言类似, 看个例子 :  下面的例子中包含了,String, Array, Hash, Set, Range, Vector, Matrix的Iterator 操作以及each方法和for语法的转换. require "Matri

Ruby Study 7 : Conditional Statements

这篇的内容很简单, 基本上都是以前用过的语法, 稍微讲的详细一点. 1. if .. then .. else #!/opt/ruby/bin/ruby def get_daytype(aDay) if (aDay.to_s.downcase == 'saturday') || (aDay.to_s.downcase == 'sunday') # 分行写的话then可以忽略. daytype = 'weekend' else daytype = 'weekday' end return dayt

Ruby Study 9 : Passing Arguments and Returning Values

1. Summarizing Instance, Class and Singleton methods Instance methods指的是可以被它所在的类的实例调用的方法. Class 方法和Singleton 方法指属于某个单独的对象的方法,不能被其他对象调用.(注意我把类方法也这么解释, 是因为类(包括BasicObject,Object,Module,Class以及自定义的类等)其实都是Class的对象.) 2. Returning Values 在很多编程语言中一般分有返回和不返回

Ruby Study 13 : Modules and Mixins

在Ruby中class的superclass只能有一个, childclass可以有多个. 所以一个class如果要继承多个class的特性是不可能的. 如果有这种需求, 可以考虑把这些特性封装在Module中. Module可以很好的解决这类问题, 通过require或者load或者include可以把Module的instance method等带入到当前环境, 也就是可以使用Module中的方法等. 一个class可包含多个Module, 接下来详细的讲解. 1. A Module Is

Ruby Study 5 : Hash, Martix, Vector and Set class

Hash class 1. introduce 前面一篇讲了一下Array, 其实Hash 和Array还是比较类似的, 只不过Hash的每个元素是由key和value组成的. 我们来看看创建Hash的几种方法. h1 = {1=>'d', 2=>'c', 3=>'b', 4=>'a'} h2 = Hash.new() h3 = Hash.new("default value") 这里分别创建了3个Hash对象, h1 有4个元素. h2和h3都没有元素, 只不