Ruby .each删除集合中的项目

时间:2010-02-16 00:07:01

标签: c# ironruby

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

SAFE = ;
return control if control.CyclesCount == 0;
control.Items.each{|item| control.Items.Remove(item) if item.Value.index('|').nil?};
return 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的忠实用户,所以对我很轻松......但我可以使用一些建议。

由于

3 个答案:

答案 0 :(得分: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返回仅包含所选元素的数组,但不会修改原始数组。

答案 1 :(得分: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

如果ListItemCollection实现IEnumerable,那么后者应该(否则我会认为IronRuby中存在错误)。如果ListItemCollection 实现IEnumerable(我可能会认为ListItemCollection中存在错误),那么这仍然很容易修复:

class ListItemCollection; include Enumerable end

[BTW:我还会在.NET端引入cycles?方法(或bool HasCycles属性),这样就可以摆脱cycle_count == 0测试。] < / p>

答案 2 :(得分:1)

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

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

然而,为了正确调试它,我们需要知道Ruby端的control.Items是什么样的。