论坛首页 编程语言技术论坛

inject的疑惑

浏览 10687 次
锁定老帖子 主题:inject的疑惑
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (1)
作者 正文
   发表时间:2007-02-27  
你能猜到下面的ruby程序输出吗?
[1,2,3].inject([]) do |a, item|
  puts a
  a << item
end

按照ruby的手册,这段的含义是:给a赋初值[],然后对[1,2,3]数组的每个元素,把元素添加到a中。

那么,我的理解,输出应该为:
[]
[1]
[1,2]

但是我错了,实际的输出是:
1
1
2
尤其是第一个1,真让我想去看看ruby的c源码了。


可是,下面这段:
[1,2,3].inject(0) do |a, item|
  puts a
  a += item
end


同样,我的理解,输出应该为:
0
1
3

这次我对了,实际的输出它怎么就是:
0
1
3

有人能告诉我为什么吗?

   发表时间:2007-02-27  
[1,2,3].inject([]) do |a, item|
  puts a
  a << item
end


没问题啊,你把上面这段代码的puts换成p再看看吧:

[1,2,3].inject([]) do |a, item|
  p a
  a << item
end


puts一个数组时它会一行输出一个元素。
0 请登录后投票
   发表时间:2007-02-28  
是我理解错puts了。

引起这段程序的根源是我犯的另一个错,结果给我的提示信息让我误以为应该是那样输出。

谢谢!

不过,还是出道小题,看看我犯过的错还有多少人会同样犯。下面这段代码有什么问题:
[1,2,3].inject([]) do |a, item|
  if item >=2 
     a << item
  end
end


0 请登录后投票
   发表时间:2007-02-28  
dcaoyuan 写道
是我理解错puts了。

引起这段程序的根源是我犯的另一个错,结果给我的提示信息让我误以为应该是那样输出。

谢谢!

不过,还是出道小题,看看我犯过的错还有多少人会同样犯。下面这段代码有什么问题:
[1,2,3].inject([]) do |a, item|
  if item >=2 
     a << item
  end
end




这个block未返回值,下一次a就变成nil了
0 请登录后投票
   发表时间:2007-02-28  
dcaoyuan 写道
是我理解错puts了。

引起这段程序的根源是我犯的另一个错,结果给我的提示信息让我误以为应该是那样输出。

谢谢!

不过,还是出道小题,看看我犯过的错还有多少人会同样犯。下面这段代码有什么问题:
[1,2,3].inject([]) do |a, item|
  if item >=2 
     a << item
  end
end




应该是这样吧:
[1,2,3].inject([]) do |a, item|
  if item >=2 
     a << item
  else
     a
  end
end
0 请登录后投票
   发表时间:2007-02-28  
对。不能遗漏else。

但是,如果用each:
a = []
[1,2,3].each do |a, item|
  if item >= 2
    a << item
  end
end

就没有任何问题,这就是我觉得ruby不一致的地方,看上去比较一致的逻辑块,结果却很不一致。

如果是Erlang,就不可能犯这种错:
lists:foldr(
    fun(Item, A) ->
        if 
            Item >= 2 -> [Item|A];
            true -> A   
        end
    end, [], [1,2,3])

这里,true -> A是必须的,否则编译无法通过。而且,选择foldr函数是很自然的,不太可能选择foreach来完成这个事,虽然也可以做到。基本上Erlang不太可能让你写出类似上面这种出错的句子。这也是我认为一门语言应该严谨的地方。
0 请登录后投票
   发表时间:2007-02-28  
如果你这样就说ruby不一致,那ruby就太冤了。
首先,您这段代码
a = []
[1,2,3].each do |a, item|
  if item >= 2
    a << item
  end
end


本身已经有两处写错了,第一,each的block参数a会影响到外围的数组a;第二,上面的item永远被附于nil。

each的最基本用法你都写错了......

再说each和inject本来就是功能完全不同的方法,使用上有所不同是完全正常的。
0 请登录后投票
   发表时间:2007-02-28  
不好意思,写得太快了,copy/paste,没注意,应该是:
a = []  
[1,2,3].each do |item|  
  if item >= 2  
    a << item  
  end  
end


我可能属于比较懒的:-) 不太喜欢脑筋转来转去,所以比较喜欢不太容易让我犯错的语言。

ruby可以用很多种方式作同一件事,这是双刃剑。
0 请登录后投票
   发表时间:2007-02-28  
我觉的这并非ruby不一致的问题,inject与each本来就是功能完全不同的方法。
0 请登录后投票
   发表时间:2007-02-28  
1) in ruby, "if" is an EXPRESSION, not STATEMENT. keep this in mind
2) checkout RDoc of "inject":
enum.inject(initial) {| memo, obj | block } => obj
enum.inject {| memo, obj | block } => obj

Combines the elements of enum by applying the block to an accumulator value (memo) and each element in turn. At each step, memo is set to the value returned by the block. The first form lets you supply an initial value for memo. The second form uses the first element of the collection as a the initial value (and skips that element while iterating).
3) i guess this is what you were looking for:
a = [1,2,3].select do |x| x >= 2 end
0 请登录后投票
论坛首页 编程语言技术版

跳转论坛:
Global site tag (gtag.js) - Google Analytics