Ruby操纵数据结构(二)

Ruby操纵数据结构(二)

8 、实现稀疏矩阵

有时候我们需要被定义元素很少的数组;它的其余元素可以末被定义( 或者通常为零) 。这称为稀疏矩阵, 历史上它是消耗内存的大户,以致让人们寻找一些间接的方法来实现它。
当然,大多数情况下,Ruby 数组足够有效了,因为典型的现代体系有大量的内存。未赋值元素有值为nil ,它只使用很少几个byte 的存储空间。

另一方面,在前一个数组元素的范围内分派数组元素,也可在两者之间创建nil 元素。例如,如果元素从0 9 被定义,我们突然赋值给第1000 个元素,则我们会有效地获得元素从10 999 ,而它们所带的是nil 值。如果这不可以接受,你也以考虑另一种选择。
然而,对于其它解决办法,我们不认为它会做的比数组更好。如果你真的需要稀疏矩阵,哈希表可以是最好的解决办法。


9 、用数组实现Set 数据集

大多数语言并不直接实现Set 数据集(Pascal 是个例外) 。但是,Ruby 数组有很多特征可以使它们被用做Set 数据集。我们在介绍它并添加一些自己的东西。( 译注:1.8 中有Set )
首先,数组可以持有重复条目。如果你想将数组视为Set 数据集,你可以移除所有重复的条目( 使用uniq uniq!)
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]
# Duplicates are removed...
e = [1, 2, 2, 3, 4]
f = [2, 2, 3, 4, 5]
g = e & f
# [2, 3, 4]
串联操作符+ 也可用于数据集Set 的并集,但是它不排除重复。- 方法是" 数据集区别" 操作符将产生包含第一个数据集的所有元素,而不含在第二个数据集中出现的元素。这儿是个例子:
a = [1, 2, 3, 4, 5]
b = [4, 5, 6, 7]
c = a - b

# [1, 2, 3]
# 注意额外的条目6 7 是不相关的。
" 堆积" 数据集,你可以使用 |= 操作符,像你想一样, a |= b 只是简单地等于 a = a | b 。同样 &= 可以次第地减少("narrow down") 数据集的元素。
是无排它的- 或对数组定义的,但我们可以很容易地实现我们自己的。数据集术语中,没有排它性- 或用于数组的定义,但我们可以非常容易地做出自己的。在数据集条目中,这对应于两个数据集的并集元素而不是交集。这儿个例子:
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?( 本质上是Comparable 模块保的别名) ,像这样:
x = [1, 2, 3]
if x.include? 2

puts "yes"
# Prints "yes"
else

puts "no"
end
当然,字面值<< 来自于我们使用的数学,这个操作符类似于希腊第五个字母代表数据集的成员。感觉上它反向的是左面而不是右面;我们不要问" 这个元素是这个数据集的吗?" 而是关心" 这个数据集包含这个元素吗?"
许多人根本就不关心这个,如果你使用Pascal Python( 或者你是数学爱好者) ,你可能想使用不同的方式。我们这有两个选择:
class Object

def in(other)



other.include? self

end
end
x = [1, 2, 3]
if 2.in x



puts "yes"
# Prints "yes"
else

puts "no"
end
例子有些难看,但至少次序我们很熟悉。至于让它看起来“更像个操作符”,Ruby 的让人不可思义的灵活的解析器允许你写表达式2.in x 代替 2 .in x 2. in x ,你可能会想的更远。
前面这些都不是标准的,我们可能基于这样的目的重写操作符比如<= 。但是,像这样的事情做起来应更小心。
这儿谈到了用于Ruby 的像Python( Pascal) 这样的操作符。但是,现在不会谈得太多。
我们会告诉你如何做而不管一个数据集是子数据集还是什么的超集。这儿没有内建的方法,但我们可以做像Listing3.4 中的那样。
Listing 3.4 Subset and Superset
class Array

def subset?(other)
#self other 的子集吗



self.each
do |x|




if !(other.include? x) # x 包含在other 内吗



return false
# 只要有一个元素不在就返回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
注意,我们选择了“自然”次序,也就是说, x.subset? y 意味着“x y 的子集吗”。反之亦然。
要查出null 数据集( 或空数据集) ,我们只简单地查看空数组。Empty? 方法会做这些。
数据集否定( 或补集) 的概念依赖于通用数据集的概念。因为实际过程中这将从一个应用或状态到另一个应用或状态,最好的方式是简单地定义一个通用数据集,然后再做交集,像下面这样:
universe = [1, 2, 3, 4, 5, 6]
a = [2, 3]
b = universe - a
# complement of a = [1, 4, 5, 6]
当然,如果你认为这很主要,你可定义一个一元操作符( - ~) 来做这些。
你可能通过对数组的迭代而达到对数据集的迭代。唯一的不同是元素没有次序,那可能不是你想要的。随机的迭代可以看"Iterating over an Array "

最后,我们可能时想要计算一个数据集的平方数据集。这可简单地所有可能的子数据集(包括空集和原始集合本身)。那么熟悉离散数学的,特别是组合数学,将看到这些必须是2n的子集。依照Listing3.5我们可以生成powerset


Listing 3.5 Powerset of a Set
class Array

def powerset

num = 2**size

ps = Array.new(num, [])

self.each_index do |i|

a = 2**i

b = 2**(i+1) - 1

j = 0

while j < num-1

for j in j+a..j+b

ps[j] += [self ]


end

j += 1

end

end

ps

end
end
x = [1, 2, 3]
y = x.powerset
# y is now:
#
[[], [1], [2], [1,2], [3], [1,3], [2,3], [1,2,3]]
译注:文档中的定义
1.
array.uniq → an_array
2.
array.uniq! → array or nil
3.
array & other_array
4.
array | other_array → an_array
5.
array + other_array → an_array
6.
array - other_array → an_array
7.
array.include?(obj) → true or false
8.
enum.include?(obj) => true or false
9.
enum.member?(obj) => true or false
10.
array.empty? → true or false
uniq会删除数组中的重复元素后生成新数组并返回它。剩下的元素会向前移动。uniq!具有破环性,若进行了删除则返回self,若没有删除则返回nil

&,| 数据集Set的交集(并集)运算。将同属于两个数组的元素重组为一个新数组并返回该数组。重复元素将被清除。若other并非数组的话,将尝试隐式地调用to_ary方法进行变换。
+ selfother的内容连起来后生成新数组并返回该数组。若other并非数组时则使用other.to_ary的返回值。若该返回值依然不是数组时,则引发TypeError异常。
- 集合的补集运算。从self中删除other的元素后生成一个新数组并返回该数组。重复元素将被清除。若other并非数组的话,将尝试隐式地调用to_ary方法进行变换。ruby 1.8 特性: 重复元素将被保留。
[ 1, 1, 2, 2, 3, 3, 4, 5 ] - [ 1, 2, 4 ]
#=>
[ 3, 3, 5 ]
译注:1.8中已提供了Set库,我们下面来看一下它有什么方法,Set类包含了Enumerable模块。
Set实现了无序的不包含重复值的集合。它混杂了数组的直观操作功能和哈希表的快速搜索。

有几个方法接受任何实现eachEnumerable对象以达到更大的灵活性: new, replace, merge, subtract, |, &, -, ^
每对元素的等同性由Object#eql?Object#hash决定,因为Set使用哈希表做为存储。

最后,如果你使用类Set,你也可以使用Enumerable#to_set带来的便利。
例子:

require 'set'

s1 = Set.new [1, 2]
# -> #<Set: {1, 2}>

s2 = [1, 2].to_set
# -> #<Set: {1, 2}>

s1 == s2
# -> true

s1.add("foo")
# -> #<Set: {1, 2, "foo"}>

s1.merge([2, 6])
# -> #<Set: {6, 1, 2, "foo"}>

s1.subset? s2

# -> false

s2.subset? s1
# -> true
类方法:
1.
[](*ary)
2.
new(enum = nil) {|o| ...}
实例方法:
1.
&(enum)
intersection(enum)
交集
2.
+(enum)
|(enum)
union(enum)
并集
3.
-(enum)
difference(enum)
差集
4.
==(set)
5.
^(enum)
排它操作,等于((set | enum) - (set & enum)).
6.
add(o)
add?(o)

<<(o)
添加对象o到集中。
7.
classify( {|o| ...}
8.
clear()
9.
collect!() {|o| ...}
map!()
10.
delete(o)

delete?(o)
从集合中删除元素o
11.
delete_if() {|o| ...} 删除块计算后为true的每个元素。
12.
divide(&func)
13.
each() {|o| ...}
为集中每个元素调用块,传递元素做为参数。
14.
empty?()
15.
flatten()
16.
flatten!()
17.
include?(o)
member?(o)
集中包含o对象吗?
18.
initialize_copy(orig)
拷贝内部Hash
19.
inspect()
20.
length()
size()
21.
merge(enum)
enumerable中的元素并入集中。


[ 本帖最后由 blackanger 于 2007-5-20 17:54 编辑 ]

 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值