0

我目前正在使用一个应用程序,该应用程序允许通过 rub 脚本在运行时添加和删除下拉列表中的项目。红宝石看起来像这样

SAFE = ;
return control if control.CyclesCount == 0;
control.Items.each{|item| control.Items.Remove(item) if item.Value.index('|').nil?};
return control;

control 是自定义用户控件,其 Items 是 ListItemCollction。我正在通过单元测试运行以使我的 Ruby 代码正确并遇到一些麻烦。我传入的 ListItemColletion 看起来像这样..

var lic = new ListItemCOllection {
  new ListItem {Text = "Item2", Value = "8"}, 
  new ListItem {Text = "Item1", Value = "1"},
  new ListItem {Text = "Item3", Value = "3|1"},
  new ListItem {Text = "Item4", Value = "4"},
  new ListItem {Text = "Item5", Value = "5|2"},
  new ListItem {Text = "Item6", Value = "6"}
}

这段代码似乎总是在 items 集合中留下 3 个项目,而不是留下 2 个项目和管道。3 取决于我放入物品的顺序(而按照这个顺序,Item1、Item3、Item5 离开)这让我相信它的移除搞砸了。我还尝试获取集合的副本,循环遍历它,从原始集合中删除,这样我就不会从正在迭代的集合中删除。我是 Ruby 的相对菜鸟,所以对我放轻松……但我可以使用一些建议。

谢谢

4

3 回答 3

5

不建议在迭代时更改数组。有一些迭代器的目的是改变数组。

a= [1,2,3]
b= [1,2,3]
a.delete_if { |x| x == 2 } # => [1,3]
b.reject! { |x| x == 2 } # => [1,3]
a # => [1,3]
b # => [1,3]

Array#delete_if删除数组的元素。只有细微的差别Array#reject

a= [1,2,3]
b= [1,2,3]
a.delete_if { |x| false } # => [1,3]
b.reject! { |x| false } # => nil
a # => [1,2,3]
b # => [1,2,3]

Array#delete_if总是返回剩余的数组。Array#reject!如果数组保持不变,则返回 nil。

更多修改迭代器,不更改原始数组:

a= [1,2,3]
a.reject { |x| x == 2 } # => [1,3]
a # => [1,2,3]

Array#reject返回一个没有被拒绝元素的数组,但不修改原始数组。

a= [1,2,3]
a.select { |x| x != 2 } # => [1,2,3]
a # => [1,3]

Array#select返回仅包含选定元素的数组,但不修改原始数组。

于 2010-02-16T00:21:54.727 回答
3

在迭代修改集合绝不是一个好主意。如果你这样做,所有的地狱都会崩溃。(最好,它会引发某种异常,但这就是生活......)

但是,这实际上并不是代码中最大的问题。最大的问题是你犯了Ruby的死罪:不知道Enumerable。(别担心:每个人都会犯那种罪。一直都是。)

如果您想拒绝集合中满足条件的所有元素,则有一种方法可以做到这一点,它的名称正是您所期望的:Enumerable#reject!.

所以,让我们清理一下,好吗?

SAFE = ;

那个分号在那里做什么?看来你把你的 C# 和 Ruby 搞混了 :-)

return control if control.CyclesCount == 0;

再次,无用的分号。

control.Items.each{|item| control.Items.Remove(item) if item.Value.index('|').nil?};

这就是有趣的地方:

control.Items.reject! {|item| item.Value.include?('|') }

好多了,不是吗?

return control;

我个人喜欢return为“纯”方法(即没有副作用的方法)保留关键字,因此我不会在这里使用关键字,因为代码会修改control.Items,但这是一种样式选择。把它们放在一起,这就是我写它的方式:

return control if control.cycles_count == 0
control.items.reject! {|item| item.value.include?('|') }
control

注意:我现在没有安装 IronRuby 的工作,所以我做了一些我很遗憾无法测试的假设:

  • 方法名称音译 ( CyclesCount-> cycles_count) 有效,
  • Value是某种String或集合和
  • ListItemCollection混入Enumerable

如果实施,后者应该是这种情况ListItemCollectionIEnumerable是这种情况(否则我会认为这是 IronRuby 中的一个错误)。如果ListItemCollection没有实现(我可能会认为这是一个错误,那仍然很容易修复:IEnumerableListItemCollection

class ListItemCollection; include Enumerable end

[顺便说一句:我还会介绍一种cycles?方法(或bool HasCycles.NET 端的属性),以便您摆脱cycle_count == 0测试。]

于 2010-02-16T00:37:39.093 回答
1

如果您只想根据条件从数组中删除项目,您应该使用Array#reject!

control.Items.reject! {|item| item.Value.index('|').nil? };

然而,为了正确调试它,我们需要知道control.ItemsRuby 端的样子。

于 2010-02-16T00:21:33.120 回答