新手问题 还是 ruby arrray delete 的问题

p_next · 2013年05月02日 · 最后由 doitian 回复于 2013年05月02日 · 2206 次阅读

我写一个玩牌的小游戏,是两副牌的,所以会有两个♠3,而我想实现的功能是,每出一个♠3,就从记录所有牌的数组(这个数组形如:[♠3 ♠3 ♠4 ♠4,,,,,])中删除这一个♠3。

现在的问题是 delete 函数,如果元素重复,会全部删除。两♠3 都被删了!

有什么办法删除第一个出现的元素么?

已经由@blacktulip提出了解决方案:

a.slice!(a.index(♠3))

这样的确可行。但是又出现了新的问题: (为了方便理解,我将 [♠3 ♠3 ♠4 ♠4..,,,,] 记为 [♠3A ♠3B ♠4A ♠4B ..,,,,])

我用的是 a.each do |ele| 当用 a.slice!(a.index(♠3)) 删除掉♠3A 是,这时的♠3B 会向前移动到♠3A 的位置, 即 index:0_123 [.......♠3A ♠3B ♠4A ♠4B ..,,,,] 变成: index:01_2
[......♠3B ♠4A ♠4B ..,,,,] 而迭代器却要向前移动一个,指向了 1 的位置,也就是♠4A 这样 ♠3B 就逃过了迭代器 请问怎么能让迭代器从新向前移动一个,让♠3B 接受迭代? 另外,我能否认为,这一系列的问题都是由于使用内部迭代器而造成的?如果我使用外部迭代器是否更方便?

a[a.index(♠3)] = nil

我倒是感觉是你这游戏的设计问题。能简略说下游戏规则么?

上..代..码...

delete 会影响迭代。 比较简单的方式是使用

a.dup.each_with_index do |ele, index|
   a.slice!(index)
end

不急着删,先只标记。

就算你用 for 循环也一样,你的数组对象在循环的时候删除一个数据,下标也位置也会向前移。所以你要想清楚啥是你想要的,这跟闭包没半毛钱关系

#1 楼 @blacktulip 标记起来是吧,谢谢你的回复

#2 楼 @raven 就是出了什么牌,就从数组从删掉。问题是数组中元素都是成对的,若指定删除♠3 那么两个♠3 都会删,如果采用 slice!,则元素会移动 会改变 index 的位置。大致就是这样一个矛盾。

#4 楼 @zlx_star 恩,谢谢。不过这种方式在删除的时候,也会由于元素被删除而发生 index 错位的情况

#5 楼 @hhuai 恩,标记可行

#6 楼 @badboy 谢谢,不过外部迭代器我可以指定每删除一个,下标也往后退一个,从而避免了 index 的错位。

#9 楼 @p_next 我错了,要这样使用

adup = a.dup
adup.each_with_index do |ele, index|
   a.slice!(index) if xxx
end

给每张牌都分配个 ID 有 4 张 ♠3 就是 ♠3_1 ♠3_2 ♠3_3 ♠3_4,这样就可以用 Set 来存放。要么用 Hash,key 是牌型,value 是剩的张数。

另外 a.slice!(a.index(♠3)) 没就删掉了嘛,还循环什么。要删除多张,多次调用就行了。另外你可以从后往前遍历,这样删掉了不影响剩下要遍历元素的位置。

需要 登录 后方可回复, 如果你还没有账号请 注册新账号