【问题标题】:explain one expression of Ruby Array uniq method解释 Ruby Array uniq 方法的一种表达式
【发布时间】:2011-10-14 15:07:30
【问题描述】:
c = %w(a b c d)
1.8.7 :025 > c.uniq {|x|x[/^a/]}
=> ["a", "b"] 
1.8.7 :026 > c.uniq {|x|x[/^b/]}
=> ["a", "b"] 
1.8.7 :027 > c.uniq {|x|x[/^c/]}
=> ["a", "c"] 
1.8.7 :029 > c.uniq {|x|x =~ [/^c/]}
=> ["a"] 
1.8.7 :030 > c.uniq {|s|s[/[^abc]/]}
=> ["a", "d"]

我了解正则表达式,但我不了解 uniq 块是如何工作的。

【问题讨论】:

    标签: ruby arrays uniq


    【解决方案1】:

    这有点棘手。

    c = %w(a b c d)
    1.8.7 :025 > c.uniq {|x|x[/^a/]}
    => ["a", "b"] 
    

    此块中的x 是数组中的每个值。您通过“字符串是否以a 开头?”来定义唯一性。值a 是第一个评估为true 的值,因此是第一个值。 b 是第一个评估为 false 的值,第二个值也是如此。 cd 也评估为 false,但不是唯一的,因为已找到评估 false 的值。

    1.8.7 :026 > c.uniq {|x|x[/^b/]}
    => ["a", "b"] 
    

    这里也一样。 a 是第一个 (false),b 是第二个 (true)。

    1.8.7 :027 > c.uniq {|x|x[/^c/]}
    => ["a", "c"] 
    

    您在这里看到a 是第一个false 值,c 是第一个评估为true 的值,因此是第二个唯一值。

    1.8.7 :029 > c.uniq {|x|x =~ [/^c/]}
    => ["a"] 
    

    在这里,您已经通过“字符串是否匹配一个匹配不以 c 开头的字符串的正则表达式数组”来定义唯一性。奇怪!

    1.8.7 :030 > c.uniq {|s|s[/[^abc]/]}
    => ["a", "d"]
    

    在这里你定义了一个字符类。您通过“包含 a、b 或 c 的字符串”定义了唯一性。 a 是第一个满足 true 的。 d 是唯一要评估为 false 的值。

    希望对您有所帮助。

    【讨论】:

    • 在细节上更正自己:x[/^a/] 表示法的意思是:在字符串x 中查找与/^a/ 匹配的所有内容。在"a" 的情况下,它将匹配整个字符串("a"),在"b" 的情况下,它的计算结果为nil。所以不是我上面说的truefalse,而是valuenil
    • 非常有帮助和清晰的解释。你是对的。最后一个表达式也是如此。 c.uniq {|s|s[/[^abc]/]} 由“不包含 a,b 或 c 的字符串”定义 uniq,因此 a,b,c 为 nil d 为 d,则结果为 ['a', 'd']。否则,如果包含 uniq,则结果将为 ['a','b','c','d']。
    • @Race:对。如果你做了c.uniq {|s|s[/[abc]/]},你会得到整个东西,但%w(a b c d e).uniq { |s| s[/[abc]/] } 可能会给你%w(a b c d)
    【解决方案2】:

    唯一性的确定是基于将每个元素传递给块的结果。

    因此,例如,第一个表示询问每个元素是否为“a”。第一个说是,所以“a”被认为是唯一的。第二个说不,所以“b”被认为是唯一的。其他人也说不,因此它们不被认为是唯一的(因为“不”的响应是我们已经看到的)。

    但是,我不能轻易解释的是为什么这在 Ruby 1.8.7 中似乎对您有用;在 1.8.7 和之前的版本中,Array#uniq 的块参数被忽略。此功能是在 Ruby 1.9 中添加的。也许你有一个补丁版本?

    【讨论】:

      【解决方案3】:

      这样看:当您将uniq 与块一起使用时,您实际上构建了一个数组数组,其中每个内部数组都是[result_of_block, array_element],然后在第一个元素中查找唯一值。所以,如果我们开始:

      c = %w(a b c d)
      

      看看

      c.uniq {|x|x[/^a/]}
      

      那么数组的数组将如下所示:

      [
          ['a', 'a'],
          [nil, 'b'],
          [nil, 'c'],
          [nil, 'd']
      ]
      

      在第一个元素中寻找唯一值会产生 'a'nil

      [
          ['a', 'a'],
          [nil, 'b']
      ]
      

      然后展开产生['a', 'b']。但不能保证您会得到 'b' 作为第二个元素。

      您可以像这样编写自己的uniq_by

      def uniq_by(a, &block)
          Hash[a.map { |x| [ block.call(x), x] }].values
      end
      

      或者这个:

      def uniq_by(a, &block)
          h = { }
          a.each { |x| h[block.call(x)] = x ] }
          h.values
      end
      

      【讨论】:

      • 太好了,这是另一种很好的理解方式。由于我们使用的方式是我们称之为“uniq_by”的方式,如果元素是散列或对象,我们应该通过散列值或散列键做一些唯一性。 1.8.7 :041 > [{"a"=>"3"}, {"a"=>"4"}, {"a"=>"3"}].uniq {|x|x.keys} => [{"a"=>"3"}] 1.8.7:042 > [{"a"=>"3"}, {"a"=>"4"}, {"a"=>" 3"}].uniq {|x|x.values} => [{"a"=>"3"}, {"a"=>"4"}]
      猜你喜欢
      • 2021-02-22
      • 2016-01-18
      • 2012-01-29
      • 1970-01-01
      • 2022-12-11
      • 2010-09-26
      • 1970-01-01
      • 2015-02-15
      • 2015-06-26
      相关资源
      最近更新 更多