2007-12-27

ruby way之Arrays

1 创建和实例化一个数组

类方法[]能够创建一个数组,这里有3种方法使用[]来创建一个数组:
a = Array.[](1,2,3,4)
b = Array[1,2,3,4]
c = [1,2,3,4]


这里还有一个方法叫做new也可以创建一个数组,它可以接受0,1或者2个参数,第一个参数是数组的大小,第二个参数是数组中每一个元素的默认值。

d = Array.new               # Create an empty array
e = Array.new(3)            # [nil, nil, nil]
f = Array.new(3, "blah")    # ["blah", "blah", "blah"]


这边要注意的是,上面的最后一个例子,这里虽然每个元素都有一个默认值,可是这些默认值指向的其实都是相同的对象。也就是说改变其中任何一个元素,剩下的元素都会改变。如果要产生出的默认值,每个都有一个对象,那就要使用一个block:

f=Array.new(3,"blah")
f[0].capitalize!            # f is now: ["Blah", "Blah", "Blah"]
puts f.to_s
g = Array.new(3) { "blah" } # ["blah", "blah", "blah"]
g[0].capitalize! 
puts g.to_s


2 存取和修改数组的元素

我们能够使用[]和[]=方法来存取数组中的元素,[]中可以放一个整数,一对整数或者一个区间。如果是负数的话就从最右边开始:

a = [1, 2, 3, 4, 5, 6]
b = a[0]                # 1
c = a.at(0)             # 1
d = a[-2]               # 5
e = a.at(-2)            # 5
f = a[9]                # nil
g = a.at(9)             # nil
h = a[3,3]              # [4, 5, 6]
i = a[2..4]             # [3, 4, 5]
j = a[2...4]            # [3, 4]

a[1] = 8                # [1, 8, 3, 4, 5, 6]
a[1,3] = [10, 20, 30]   # [1, 10, 20, 30, 5, 6]
a[0..3] = [2, 4, 6, 8]  # [2, 4, 6, 8, 5, 6]
a[-1] = 12              # [2, 4, 6, 8, 5, 12]


注意下面的例子,当我们想付给数组的元素太多时,将会发生什么:

k = [2, 4, 6, 8, 10]
k[1..2] = [3, 3, 3]     # [2, 3, 3, 3, 8, 10]
k[7] = 99               # [2, 3, 3, 3, 8, 10, nil, 99]
puts k.to_s

上面的例子可以看出,当元素太多时,数组会自动增长.

我们如果把一个数组付给一个数组元素,这时将会产生一个嵌套数组:

m = [1, 3, 5, 7, 9]
m[2] = [20, 30]         # [1, 3, [20, 30], 7, 9]

puts m.to_s
# On the other hand...
m = [1, 3, 5, 7, 9]
m[2..2] = [20, 30]      # [1, 3, 20, 30, 7, 9]
puts m.to_s


方法slice是[]方法的别名:
x = [0, 2, 4, 6, 8, 10, 12]
a = x.slice(2)               # 4
b = x.slice(2,4)             # [4, 6, 8, 10]
c = x.slice(2..4)            # [4, 6, 8]


方法first和last返回数组第一个和最后一个元素:

x = %w[alpha beta gamma delta epsilon]
a = x.first      # "alpha"
b = x.last       # "epsilon"


你如果想得到数组中某几个元素组成的数组,你可以使用values_at方法:

x = [10, 20, 30, 40, 50, 60]
y = x.values_at(0, 1, 4)        # [10, 20, 50]
z = x.values_at(0..2,5)         # [10, 20, 30, 60]


3 得到一个数组的大小

方法length和它的别名size能够返回一个数组的大小
x = ["a", "b", "c", "d"]
a = x.length               # 4
b = x.size                 # 4


方法nitems 也是返回数组的大小,不过他计算时不会包括nil的值:

y = [1, 2, nil, nil, 3, 4]
c = y.size                 # 6
d = y.length               # 6
e = y.nitems               # 4


4 比较数组

实例方法<=>被使用来比较两个数组,两个数组比较小于返回-1,等于返回0,大于返回1.方法==和!=依赖于<=>方法。

<=>方法的比较是一个元素一个元素进行,遇到相等的,就往下走:

a = [1, 2, 3, 9, 9]
b = [1, 2, 4, 1, 1]
c = a <=> b            #由于a[2]<b[2]所以a<b -1 (meaning a < b)


如果两个数组每一个对应元素都相等,那么这两个数组就相等,如果两个数组不一样长的话,那就只比到短的元素的结尾:

d = [1, 2, 4]
e = [1, 2, 3, 4]
f = [1, 2, 3]
puts d<=>e
puts d<=>f


由于array没有mix comparable模块,因此 <, >, <=, 和>=方法,并不能用,我们可以include comparable模块,就能使用这些方法了:

if a < b
  print "a < b"       # Prints "a < b"
else
  print "a >= b"
end
if d < e
  puts "d < e"        # Prints "d < e"
end


当两个不同类型的元素进行比较时就会报错:

d = [1, 2, "3"]
e = [1, 2, 3, 4]
f = [1, 2, 3]
class Array
  include Comparable
end
puts d<e #这边会出错,因为"3" <=>3 时,会报错


可是!=和=方法却是可以正常使用:

if g != h             # No problem here.
  puts "g != h"       # Prints "g != h"
end


可以看下下面的例子:
i = [1, 2, 3]
j = [1, 2, 3, "x"]
if i < j             # No problem here.
  puts "i < j"       # Prints "i < j"
end


这边可以清楚的看到,j的最后一个元素没有参与比较.

5排序一个数组

最简单的排序一个数组的方法是使用内置的sort方法:
words = %w(the quick brown fox)
list = words.sort  # ["brown", "fox", "quick", "the"]
puts list.to_s
# Or sort in place:
words.sort!        # ["brown", "fox", "quick", "the"]


sort方法假设数组里面没一个元素都是可比较的,因此比如[1, 2, "tHRee", 4]这样的数组,进行排序的话,就会报错.

我们还可以使用一种更灵活的排序方式,那就是使用sort的block版本:

a = [1, 2, "three", "four", 5, 6]
b = a.sort {|x,y| x.to_s <=> y.to_s}  #x,y分别是每次传进来的两个元素.
# b is now [1, 2, 5, 6, "four", "three"]
x = [1, 4, 3, 5, 2]
y = x.sort {|a,b| b <=> a}    # [5, 4, 3, 2, 1]


当我们想要根据很多key来排序的话,我们使用sort方法,就显得非常麻烦,这个时候我们能够使用Enumerable 模块的sort_by方法:
words=[1,2,"3"]
puts words.sort
puts lists =words.sort_by{|item| item.to_s}


如果是多个key我们就可以使用一个数组,这里假设数组list里的对象有name,age, height三个属性,我们想依次按照这3个key排序,我们就可以这样做:

list = list.sort_by {|x| [x.name, x.age, x.height] }


6 通过一定的规则来选择出元素

比如给定一个数组,我们想把这个数组中第一个的偶数取出来,这时我们可以使用detect 方法:

x = [5, 8, 12, 9, 4, 30]
#得到第一个偶数
x.detect {|e| e % 2 == 0 }         # 8
# 得到第一个7的倍数
x.detect {|e| e % 7 == 0 }         # nil


find 方法和detect是同意的,如果我们想得到这个数组中所有的偶数,这是就该使用find_all方法,而select和find_all方法是同意的:

# Continuing the above example...
x.find {|e| e % 2 == 0}            # 8
x.find_all {|e| e % 2 == 0}        # [8, 12, 4, 30]
x.select {|e| e % 2 == 0}          # [8, 12, 4, 30]


grep方法调用===方法来匹配数组中的每一个元素与他自己所带的参数.由于是使用===方法,因此grep方法的参数不需要是正则表达式:

a = %w[January February March April May]
a.grep(/ary/)      # ["January, "February"]
b = [1, 20, 5, 7, 13, 33, 15, 28]
b.grep(12..24)     # [20, 13, 15]


如果使用它的block版本的话,那就更灵活,这样可以再次处理所匹配的元素:

# Continuing above example...
# Let's store the string lengths
a.grep(/ary/) {|m| m.length}     # [7, 8]
# Let's square each value
b.grep(12..24) {|n| n*n}         # {400, 169, 225}


reject方法和select完全相反,看名字就知道了,它是选择不符合条件的:

c = [5, 8, 12, 9, 4, 30]
d = c.reject {|e| e % 2 == 0}    # [5, 9]
c.reject! {|e| e % 3 == 0}
# c is now [5, 8, 4]


min 和max方法,返回一个数组中的最大和最小值,没有block的事使用默认的比较,如果使用block,则是可以自定义:

a = %w[Elrond Galadriel Aragorn Saruman Legolas]
b = a.min                                 # "Aragorn"
c = a.max                                 # "Saruman"
d = a.min {|x,y| x.reverse <=> y.reverse} # "Elrond"
e = a.max {|x,y| x.reverse <=> y.reverse} # "Legolas"


index返回所传入的参数是数组元素的第几个元素:

i = a.index a.min     # 2
j = a.index a.max     # 3


7 使用数组作为数学的集合

ruby的数组能很好的支持数学的集合的操作,可是如果你想使用更好的,那你可以使用内置库里面的set方法:

a = [1, 2, 3, 4, 5]
b = [3, 4, 5, 6, 7]
c = a | b            # [1, 2, 3, 4, 5, 6, 7]
d = a & b            # [3, 4, 5]

#移除重复的元素..
e = [1, 2, 2, 3, 4]
f = [2, 2, 3, 4, 5]
g = e & f            # [2, 3, 4]


-是从一个集合里面去除掉另外一个集合里面含有的第一个集合里的东西:

a = [1, 2, 3, 4, 5]
b = [4, 5, 6, 7]
c = a - b            # [1, 2, 3] 注意没有6,7


array并没有定义异或操作,可是我们能够自己定义异或操作:

class Array

  def ^(other)
    (self | other) - (self & other)
  end

end

x = [1, 2, 3, 4, 5]
y = [3, 4, 5, 6, 7]
z = x ^ y            # [1, 2, 6, 7]

要检测一个元素是否属于一个集合我们能够使用include?或者member? :

x = [1, 2, 3]
if x.include? 2
  puts "yes"     # Prints "yes"
else
  puts "no"
end


我们如果要判断一个集合是否是另一个集合的子集合,尽管没有内置的方法,可是我们能够自己定义:

class Array

  def subset?(other)
    self.each  do |x|
      if !(other.include? x)
        return false
      end
    end
    true
  end

  def superset?(other)
    other.subset?(self)
  end

end

a = [1, 2, 3, 4]
b = [2, 3]
c = [2, 3, 4, 5]

flag1 = c.subset? a     # false
flag2 = b.subset? a     # true
flag3 = c.superset? b   # true


8 将一个数组随机显示,也就是打乱掉
我们可以使用kernel的rand方法.
class Array

  def randomize
    self.sort_by { rand }    # sort by a key which is a
  end                        #  random number

  def randomize!
    self.replace(self.randomize)
  end

end

x = [1, 2, 3, 4, 5]
y = x.randomize      # [3, 2, 4, 1, 5]
x.randomize!         # x is now [3, 5, 4, 1, 2]


9 多维数组

如果你想要使用多维数组,你可以使用NArray 库。

这边我们自己定义了一个三维数组:

class Array3

  def initialize
     @store = [[[]]]
  end

  def [](a,b,c)
    if @store[a]==nil ||
       @store[a][b]==nil ||
       @store[a][b][c]==nil
      return nil
    else
      return @store[a][b][c]
    end
  end

  def []=(a,b,c,x)
    @store[a] = [[]] if @store[a]==nil
    @store[a][b] = [] if @store[a][b]==nil
    @store[a][b][c] = x
  end

end


x = Array3.new
x[0,0,0] = 5
x[0,0,1] = 6
x[1,2,3] = 99

puts x[1,2,3] #我们现在能这样的存取多维数组,而不是x[1][2][3]


10找出在一个数组中而不在另一个数组中的元素

得到两个数组里面一个里面有,另一个数组没有的元素:
text = %w[the magic words are squeamish ossifrage]
dictionary = %w[an are magic the them these words]
# Find potential misspellings
unknown = text - dictionary   # ["squeamish", "ossifrage"]


11数组的变换或者映射

我们能够使用collect,方法来操作数组,她也就是和一般函数式语言里面的map函数一样,将会返回一个新的数组,正好ruby中也有map方法,它是collect方法的别名:

x = %w[alpha bravo charlie delta echo foxtrot]
# Get the initial letters
a = x.collect {|w| w[0..0]}        # 对每一个元素应用 [0..0] %w[a b c d e f]
# Get the string lengths
b = x.collect {|w| w.length}       # [5, 5, 7, 5, 4, 7]
# map is just an alias
c = x.map {|w| w.length}           # [5, 5, 7, 5, 4, 7]




12从一个数组移除掉一个nil的值

我么能使用compact方法:

a = [1, 2, nil, 3, nil, 4, 5]
b = a.compact     # [1, 2, 3, 4, 5]
a.compact!        # a is now [1, 2, 3, 4, 5]


13 删除掉重复的数组元素

我们能够使用delete_at方法来删除一个指定位置的元素:

a = [10, 12, 14, 16, 18]
a.delete_at(3)              # 删除 第三个元素(从0开始) Returns 16
# a is now [10, 12, 14, 18]
a.delete_at(9)              # Returns nil (out of range)


我们还能使用delete方法来删除一个指定的元素:

b = %w(spam spam bacon spam eggs ham spam)
b.delete("spam")            # Returns "spam"
# b is now ["bacon", "eggs", "ham"]
b.delete("caviar")          # Returns nil


delete还能跟上一个block,block的意思就是如果找不到那个元素就会返回block:

c = ["alpha", "beta", "gamma", "delta"]
c.delete("delta") { "Nonexistent" }
# Returns "delta" (block is never evaulated)
c.delete("omega") { "Nonexistent" }
# Returns "Nonexistent"


delete_if方法将会通过block来删除元素;

email = ["job offers", "greetings", "spam", "news items"]
# Delete  长度等于4的元素
email.delete_if {|x| x.length==4 }
# email is now ["job offers", "greetings", "news items"]


shift和pop方法,也能删除数组中的元素:
x = [1, 2, 3, 4, 5]
x.pop                   # Delete the last element
# x is now [1, 2, 3, 4]
x.shift                 # Delete the first element
# x is now [2, 3, 4]


clear方法将会删除一个数组中的所有元素。

14数组的拼接和附加

这个很简单,就看代码就行了:

x = [1, 5, 9]
x << 13        # x is now [1, 5, 9, 13]
x << 17 << 21  # x is now [1, 5, 9, 13, 17, 21]

x = [1,2]
y = [3,4]
z = [5,6]
b = y + z         # [3,4,5,6]
b += x            # [3,4,5,6,1,2]
z.concat y        # z is now [5,6,3,4]


15迭代一个数组

我么能够使用reverse_each 来反响迭代一个数组:

words = %w(Son I am able she said)
str = ""
words.reverse_each { |w| str += "#{w} "}
# str is now "said she able am I Son "


each_with_index 方法的block将会多出一个index参数,使我们更容易操作:

x = ["alpha", "beta", "gamma"]
x.each_with_index do |x,i|
  puts "Element #{i} is #{x}"
end
# Produces three lines of output


16转换成一个字符串

我们能够使用join方法:

been_there = ["Veni", "vidi", "vici."]
journal = been_there.join(", ")        # "Veni, vidi, vici."

letters = ["Phi","Mu","Alpha"]
musicians = letters.join(" ")          # "Phi Mu Alpha"

people = ["Bob","Carol","Ted","Alice"]
movie = people * " and "
# movie is now "Bob and Carol and Ted and Alice"


17反转一个数组

使用reverse 方法:

inputs = ["red", "green", "blue"]
outputs = inputs.reverse          # ["green","blue","red"]
priorities = %w(eat sleep code)
priorities.reverse!               # ["code","sleep","eat"]


18移除掉重复的元素

使用uniq方法:

breakfast = %w[spam spam eggs ham eggs spam]
lunch = breakfast.uniq   # ["spam","eggs","ham"]
breakfast.uniq!          # breakfast has changed now


19数组的交叉

我们想要交叉两个数组,合并为一个数组,我们可以使用zip方法:

a = [1, 2, 3, 4]
b = ["a", "b", "c", "d"]
c = a.zip(b)
# c is now [[1,"a"], [2,"b"], [3,"c"], [4,"d"]]
# Use flatten if you want to eliminate the nesting
d = c.flatten
# d is now [1, "a", 2, "b", 3, "c", 4, "d"]
评论
发表评论

您还没有登录,请登录后发表评论

simohayha
搜索本博客
存档
最新评论