美文网首页
第 13 章 数组类

第 13 章 数组类

作者: 南北东西总相随 | 来源:发表于2017-10-07 17:24 被阅读0次

    第 13 章 数组类

    13.1 复习数组

    数组是带索引的对象的集合。

    # 使用 [] 创建数组
    >> names = ["Mike", "Tom", "Jim", "Ken"]
    => ["Mike", "Tom", "Jim", "Ken"]
    
    # 可以从数组中获取某个索引的元素(对象)
    >> names[2]
    => "Jim"
    
    # 可以将任意的值(对象)保存到数组的某个索引的元素中
    >> names[0] = "Alex"
    => "Alex"
    >> names
    => ["Alex", "Tom", "Jim", "Ken"]
    
    # 使用迭代器可以逐个取出数组中的元素
    => ["Alex", "Tom", "Jim", "Ken"]
    >> names.each{|name| puts name}
    Alex
    Tom
    Jim
    Ken
    

    13.2 数组的创建方法

    使用 [] 创建数组

    >> nums = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> strs = ["a", "b", "c", "d"]
    => ["a", "b", "c", "d"]
    

    13.2.1 使用 Array.new

    创建类的实例时使用的 new 方法,创建数组时也同样可以使用。

    
    # 若 new 方法没有参数,则会创建元素个数为 0 的数组
    >> a = Array.new
    => []
    
    # 若 new 方法只有 1 个参数,则会创建元素个数为该参数个数,且各元素初始值都为 nil 的数组。
    >> Array.new(5)
    => [nil, nil, nil, nil, nil]
    
    # 若 new 方法有两个参数, 则第 1 个参数代表元素的个数,第 2 个参数代表元素值的初始值。
    >> Array.new(5, 0)
    => [0, 0, 0, 0, 0]
    

    13.2.2 使用 %w%i

    使用 %w 创建不包含空白的字符串数组

    >> lang = %w(Ruby Perl Python Scheme Pike REBOL)
    => ["Ruby", "Perl", "Python", "Scheme", "Pike", "REBOL"]
    

    使用 %i 创建符号数组

    >> lang = %i(Ruby Perl Python Scheme Pike REBOL)
    => [:Ruby, :Perl, :Python, :Scheme, :Pike, :REBOL]
    

    13.2.3 使用 to_a 方法

    很多类都定义了 to_a 方法,该方法能把该类的对象转换为数组。

    # 对散列对象使用 to_a 方法,结果就会得到相应的数组的数组。
    >> color_table = {black: "#000000", white: "#FFFFFF"}
    => {:black=>"#000000", :white=>"#FFFFFF"}
    >> color_table.to_a
    => [[:black, "#000000"], [:white, "#FFFFFF"]]
    

    13.2.4 使用字符串的 split 方法

    对用逗号或者空白间隔的字符串使用 split 方法,也可以创建数组。

    >> column = "2013/05/30 22:33 foo.html proxy.example.jp".split()
    => ["2013/05/30", "22:33", "foo.html", "proxy.example.jp"]
    

    13.3 索引的使用方法

    13.3.1 获取元素

    通过 [] 指定索引,获取元素。

    >> alpha = ["a", "b", "c", "d", "e"]
    => ["a", "b", "c", "d", "e"]
    
    # 数组的索引从 0 开始
    >> alpha[1]
    => "b"
    
    # 索引值为负数时,从数组的末尾开始获取元素。
    >> alpha[-1]
    => "e"
    >> alpha[-2]
    => "d"
    
    # 指定索引范围,创建新数组并返回。
    >> alpha[1..3] # 包括索引为 3 的元素
    => ["b", "c", "d"]
    >> alpha[1...3] # 不包括索引为 3 的元素
    => ["b", "c"]
    >> alpha[1..7] # 索引值比数组长度大时,返回数组最后一个元素。
    => ["b", "c", "d", "e"]
    
    # 从某个元素开始,获取多个元素。
    >> alpha[2, 2]
    => ["c", "d"]
    >> alpha[2, 3]
    => ["c", "d", "e"]
    

    通过数组方法指定索引,获取元素。

    >> alpha.at(1)
    => "b"
    >> alpha.at(-1)
    => "e"
    >> alpha.at(-2)
    => "d"
    >> alpha.slice(1)
    => "b"
    >> alpha.slice(-1)
    => "e"
    >> alpha.slice(-2)
    => "d"
    >> alpha.slice(1..3)
    => ["b", "c", "d"]
    >> alpha.slice(1...3)
    => ["b", "c"]
    >> alpha.slice(1..7)
    => ["b", "c", "d", "e"]
    >> alpha.slice(2, 2)
    => ["c", "d"]
    >> alpha.slice(2, 3)
    => ["c", "d", "e"]
    

    13.3.2 元素赋值

    对一个元素赋值

    >> alpha = ["a", "b", "c", "d", "e", "f"]
    => ["a", "b", "c", "d", "e", "f"]
    >> alpha[1] = "B"
    => "B"
    >> alpha[4] = "E"
    => "E"
    >> alpha
    => ["a", "B", "c", "d", "E", "f"]
    

    对多个元素赋值

    >> alpha = ["a", "b", "c", "d", "e", "f"]
    => ["a", "b", "c", "d", "e", "f"]
    >> alpha[2, 3] = ["C", "D", "E"]
    => ["C", "D", "E"]
    >> alpha
    => ["a", "b", "C", "D", "E", "f"]
    

    13.3.3 插入元素

    插入元素其实也可以被认为是对 0 个元素进行赋值。因此,指定 [0, n] 后,就会在索引值为 n 的元素前插入元素。

    >> alpha = ["a", "b", "c", "d", "e", "f"]
    => ["a", "b", "c", "d", "e", "f"]
    >> alpha[2, 0] = ["X", "Y"]
    => ["X", "Y"]
    >> alpha
    => ["a", "b", "X", "Y", "c", "d", "e", "f"]
    

    13.3.4 通过多个索引创建数组

    使用 values_at 方法,可以利用多个索引来分散获取多个元素,并用它们创建新数组。

    >> alpha = %w(a b c d e f)
    => ["a", "b", "c", "d", "e", "f"]
    >> alpha.values_at(1, 3, 5)
    => ["b", "d", "f"]
    

    13.4 作为集合的数组

    >> ary1 = ["a", "b", "c"]
    => ["a", "b", "c"]
    >> ary2 = ["b", "c", "d"]
    => ["b", "c", "d"]
    
    # 交集运算
    >> ary1 & ary2
    => ["b", "c"]
    
    # 并集运算
    >> ary1 | ary2
    => ["a", "b", "c", "d"]
    
    # 差集运算
    >> ary1 - ary2
    => ["a"]
    

    |+ 的不同点

    >> num = [1, 2, 3]
    => [1, 2, 3]
    >> even = [2, 4, 6]
    => [2, 4, 6]
    >> num + even
    => [1, 2, 3, 2, 4, 6]
    >> num | even
    => [1, 2, 3, 4, 6]
    

    13.5 作为列的数组

    队列:按元素被追加时的顺序来获取元素的数据结构,也就是“先进先出”。

    栈:按与元素被追加时的顺序相反的顺序来获取元素的数据结构,也就是“后进先出”。

    操作数组开头与末尾的元素的方法

    元素操作 对数组开头的元素操作 对数组末尾的元素操作
    追加元素 unshift push
    删除元素 shift pop
    引用元素 first last
    >> alpha = ["b", "c", "d", "e"]
    => ["b", "c", "d", "e"]
    
    # 在数组的开头插入元素
    >> alpha.unshift("A")
    => ["A", "b", "c", "d", "e"]
    >> alpha
    => ["A", "b", "c", "d", "e"]
    
    # 删除数组开头的元素并将其作为返回值
    >> alpha.shift
    => "A"
    >> alpha
    => ["b", "c", "d", "e"]
    
    >> alpha = ["a", "b", "c", "d"]
    => ["a", "b", "c", "d"]
    
    # 在数组的末尾插入元素
    >> alpha.push("E")
    => ["a", "b", "c", "d", "E"]
    >> alpha
    => ["a", "b", "c", "d", "E"]
    
    # 删除数组末尾的元素并将其作为返回值
    >> alpha.pop
    => "E"
    >> alpha
    => ["a", "b", "c", "d"]
    
    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    
    # 获取数组开头的元素
    >> a.first
    => 1
    
    # 获取数组末尾的元素
    >> a.last
    => 5
    

    队列的实现:先进先出

    >> queue = []
    => []
    >> queue.push("a")
    => ["a"]
    >> queue.push("b")
    => ["a", "b"]
    >> queue.push("c")
    => ["a", "b", "c"]
    >> queue.shift
    => "a"
    >> queue
    => ["b", "c"]
    >> queue.shift
    => "b"
    >> queue
    => ["c"]
    >> queue.shift
    => "c"
    >> queue
    => []
    

    栈的实现:后进先出

    >> stack = []
    => []
    >> stack.push("a")
    => ["a"]
    >> stack.push("b")
    => ["a", "b"]
    >> stack.push("c")
    => ["a", "b", "c"]
    >> stack.pop
    => "c"
    >> stack
    => ["a", "b"]
    >> stack.pop
    => "b"
    >> stack
    => ["a"]
    >> stack.pop
    => "a"
    >> stack
    => []
    

    13.6 主要的数组的方法

    13.6.1 为数组添加元素

    • a.unshift(item)

    将 item 元素添加到数组的开头

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.unshift(0)
    => [0, 1, 2, 3, 4, 5]
    >> a
    => [0, 1, 2, 3, 4, 5]
    
    • a << itema.push(item) 是等价的方法

    在数组的末尾插入元素

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a << 6
    => [1, 2, 3, 4, 5, 6]
    >> a.push(7)
    => [1, 2, 3, 4, 5, 6, 7]
    
    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    
    # concat 是具有破坏性的方法,原有数组会被改变。
    >> a.concat([8, 9])
    => [1, 2, 3, 4, 5, 8, 9]
    >> a
    => [1, 2, 3, 4, 5, 8, 9]
    
    # 而 + 则会返回一个新创建的数组,原有数组不会被改变。
    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a + [8, 9]
    => [1, 2, 3, 4, 5, 8, 9]
    >> a
    => [1, 2, 3, 4, 5]
    
    • a[n] = item a[n..m] = item(s) a[n, len] = item(s)

    把数组 a 指定范围的元素替换为 item(s)

    >> a = [1, 2, 3, 4, 5, 6, 7, 8]
    => [1, 2, 3, 4, 5, 6, 7, 8]
    >> a[2..4] = 0
    => 0
    >> a
    => [1, 2, 0, 6, 7, 8]
    >> a[1, 3] = 9
    => 9
    >> a
    => [1, 9, 7, 8]
    

    专栏:具有破坏性的方法

    会改变方法(也成为消息)接收者对象值的方法称为具有破坏性的方法。使用具有破坏性的方法时要特别小心,因为当有变量也引用了接收者对象时,如果接收者对象发生了改变,变量值也会随之发生变化。

    >> a = [1, 2, 3, 4]
    => [1, 2, 3, 4]
    >> b = a
    => [1, 2, 3, 4]
    >> b.pop
    => 4
    >> b
    => [1, 2, 3]
    >> a
    => [1, 2, 3]
    

    在 Ruby 的方法中,有像 sortsort! 这样,在相同方法名后加上 ! 的方法。为了区分方法是否具有破坏性,在具有破坏性的方法末尾添加 !

    # 不具有破坏性的方法
    >> a = [1, 3, 2, 5, 4]
    => [1, 3, 2, 5, 4]
    >> a.sort
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 3, 2, 5, 4]
    
    # 具有破坏性的方法
    >> a = [1, 3, 2, 5, 4]
    => [1, 3, 2, 5, 4]
    >> a.sort!
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 2, 3, 4, 5]
    

    13.6.2 从数组中删除元素

    • 从数组中删除所有 nil 元素

    a.compact
    a.compact!

    >> a = [1, nil, 3, nil, nil]
    => [1, nil, 3, nil, nil]
    >> a.compact!
    => [1, 3]
    >> a
    => [1, 3]
    
    • 从数组中删除指定索引的元素

    a.delete_at(n)

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.delete_at(2)
    => 3
    
    • 删除满足条件的元素

    a.delete_if{ |item| ... }

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.delete_if{|i| i > 3}
    => [1, 2, 3]
    >> a
    => [1, 2, 3]
    

    a.reject{ |item| ... }
    a.reject!{ |item| ... }

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.reject!{|i| i > 3}
    => [1, 2, 3]
    >> a
    => [1, 2, 3]
    
    • 删除指定范围的元素

    a.slice!(n)

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.slice!(1)
    => 2
    >> a
    => [1, 3, 4, 5]
    

    a.slice!(n..m)

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.slice!(1..3)
    => [2, 3, 4]
    >> a
    => [1, 5]
    

    a.slice!(n, len)

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.slice!(1, 2)
    => [2, 3]
    >> a
    => [1, 4, 5]
    
    • 删除数组中重复的元素

    a.uniq
    a.uniq!

    >> a = [1, 2, 3, 4, 2, 1]
    => [1, 2, 3, 4, 2, 1]
    >> a.uniq!
    => [1, 2, 3, 4]
    >> a
    => [1, 2, 3, 4]
    
    • 删除数组开头的元素

    a.shift

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.shift
    => 1
    >> a
    => [2, 3, 4, 5]
    
    • 删除数组末尾的元素

    a.pop

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.pop
    => 5
    >> a
    => [1, 2, 3, 4]
    

    13.6.3 替换数组元素

    • 数组映射

    a.collect { |item| ... }
    a.collect!{ |item| ... }

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.collect!{|item| item * 2}
    => [2, 4, 6, 8, 10]
    >> a
    => [2, 4, 6, 8, 10]
    

    a.map { |item| ... }
    a.map! { |item| ... }

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.map!{|item| item * 2}
    => [2, 4, 6, 8, 10]
    >> a
    => [2, 4, 6, 8, 10]
    
    • 数组平铺

    a.fill(value)

    >> [1, 2, 3, 4, 5].fill(0)
    => [0, 0, 0, 0, 0]
    

    a.fill(value, begin)

    >> [1, 2, 3, 4, 5].fill(0, 2)
    => [1, 2, 0, 0, 0]
    

    a.fill(value, begin, len)

    >> [1, 2, 3, 4, 5].fill(0, 2, 2)
    => [1, 2, 0, 0, 5]
    

    a.fill(value, n..m)

    >> [1, 2, 3, 4, 5].fill(0, 2..3)
    => [1, 2, 0, 0, 5]
    
    • 展开嵌套数组

    a.flatten
    a.flatten!

    >> a = [1, [2, [3]], [4], 5]
    => [1, [2, [3]], [4], 5]
    >> a.flatten!
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 2, 3, 4, 5]
    
    • 反转数组的顺序

    a.reverse a.reverse!

    >> a = [1, 2, 3, 4, 5]
    => [1, 2, 3, 4, 5]
    >> a.reverse!
    => [5, 4, 3, 2, 1]
    >> a
    => [5, 4, 3, 2, 1]
    
    • 对数组进行排序

    a.sort
    a.sort!
    a.sort{ |i, j| ... }
    a.sort!{ |i, j| ... }
    没有块时,使用 <=> 运算符比较

    >> a = [2, 4, 3, 5, 1]
    => [2, 4, 3, 5, 1]
    >> a.sort!
    => [1, 2, 3, 4, 5]
    >> a
    => [1, 2, 3, 4, 5]
    
    • 根据数组映射对数组的所有元素进行排序

    a.sort_by{ |i| ... }

    >> a = [2, 4, 3, 5, 1]
    => [2, 4, 3, 5, 1]
    >> a.sort_by{|i| -i}
    => [5, 4, 3, 2, 1]
    >> a
    => [2, 4, 3, 5, 1]
    

    13.7 数组与迭代器

    典型的迭代器 each

    >> [1, 4, 5, 3, 2].each{|item| puts item}
    1
    4
    5
    3
    2
    => [1, 4, 5, 3, 2]
    

    接收者不是数组时,为了让迭代器的执行结果作为某个对象返回,也会用到数组。

    >> a = 1..5
    => 1..5
    >> a.collect{|i| i += 2}
    => [3, 4, 5, 6, 7]
    >> a
    => 1..5
    

    13.8 处理数组中的元素

    13.8.1 使用循环与索引

    list = ["a", "b", "c", "d"]
    for i in 0..3
        print "第 ", i+1, " 个元素是 ", list[i], "。\n"
    end
    

    结果:

    第 1 个元素是 a。
    第 2 个元素是 b。
    第 3 个元素是 c。
    第 4 个元素是 d
    
    list = [1, 3, 5, 7, 9]
    sum = 0
    for i in 0..4
        sum += list[i]
    end
    print "合计:", sum, "\n"
    

    结果:

    合计:25
    

    13.8.2 使用 each 方法逐个获取元素

    list = [1, 3, 5, 7, 9]
    sum = 0
    list.each do |elem|
        sum += elem
    end
    print "合计:", sum, "\n"
    

    结果:同上

    list = ["a", "b", "c", "d"]
    list.each_with_index do |elem, i|
        print "第 ", i+1, " 个元素是 ", elem, "。\n"
    end
    

    结果:同上

    13.8.3 使用具有破坏性的方法实现循环

    a = [10, 20, 30, 40, 50]
    while item = a.pop
        puts item
    end
    puts "After While: a = #{a}"
    

    结果:

    50
    40
    30
    20
    10
    After While: a = []
    

    13.9 数组的元素

    13.9.1 使用简单的矩阵

    >> a = [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    => [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    >> a[1][2]
    => 6
    

    13.9.2 初始化时的注意事项

    各个元素引用同一个对象

    >> a = Array.new(3, [0, 0, 0])
    => [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    >> a[0][1] = 2
    => 2
    >> a
    => [[0, 2, 0], [0, 2, 0], [0, 2, 0]]
    

    指定 new 方法的块和元素个数,程序调用与元素个数一样次数的块,然后再将块的返回值赋值给元素。每次调用块都会生成新的对象,这样一来,各个元素引用同一个对象的问题就不会发生了。

    a = Array.new(3) do
        [0, 0, 0]    
    end
    p a
    
    a[0][1] = 2
    p a
    

    结果:

    [[0, 0, 0], [0, 0, 0], [0, 0, 0]]
    [[0, 2, 0], [0, 0, 0], [0, 0, 0]]
    

    另一个例子

    >> a = Array.new(5){|i| i + 1}
    => [1, 2, 3, 4, 5]
    

    13.10 同时访问多个数组

    ary1 = [1, 2, 3, 4, 5]
    ary2 = [10, 20, 30, 40, 50]
    ary3 = [100, 200, 300, 400, 500]
    
    result = []
    
    ary1.zip(ary2, ary3) do |a, b, c|
        result << a + b + c
    end
    
    p result
    

    结果

    [111, 222, 333, 444, 555]
    

    相关文章

      网友评论

          本文标题:第 13 章 数组类

          本文链接:https://www.haomeiwen.com/subject/cgnjyxtx.html