Есть ли в Ruby что-то вроде понимания списка Python?

Python имеет приятную особенность:

print([j**2 for j in [2, 3, 4, 5]]) # => [4, 9, 16, 25]

В Ruby это даже проще:

puts [2, 3, 4, 5].map{|j| j**2}

но если речь идет о вложенных циклах, Python выглядит более удобным.

В Python мы можем сделать это:

digits = [1, 2, 3]
chars = ['a', 'b', 'c']    
print([str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a'])    
# => ['2a', '3a']

Эквивалент в Ruby:

digits = [1, 2, 3]
chars = ['a', 'b', 'c']
list = []
digits.each do |d|
    chars.each do |ch|
        list.push d.to_s << ch if d >= 2 && ch == 'a'
    end
end
puts list

Есть ли в Ruby что-то похожее?

 defhlt03 июл. 2012 г., 23:32
@RBK хорошо, да, но речь идет не о вложенных циклах (массивы 1+)
 Bharat03 июл. 2012 г., 23:27
Нечто подобное обсуждается здесь:stackoverflow.com/questions/310426/list-comprehension-in-ruby
 abarnert03 июл. 2012 г., 23:32
Короткая версия состоит в том, что в Ruby есть несколько разных вещей, которые похожи друг на друга, но ничто не является абсолютно одинаковым, и ничего более краткого (или удобочитаемого). Длинная версия & # x2026; ответ РБК связан с.
 abarnert03 июл. 2012 г., 23:44
Некоторые из ответов на этот вопрос масштабируются до вложенных циклов, а некоторые нет.

Ответы на вопрос(3)

Решение Вопроса

перечислимый а такжемассив методы достижения того же:

digits.product(chars).select{ |d, ch| d >= 2 && ch == 'a' }.map(&:join)

Это всего на 4 или более символов длиннее, чем понимание списка, и столь же выразительно (ИМХО, конечно, но, поскольку понимание списка - это просто специальное применение монады списка, можно утверждать, что, вероятно, возможно адекватно перестроить это с использованием Ruby). ; s методы сбора), не требуя какого-либо специального синтаксиса.

в Ruby нет синтаксического сахара для составления списков, поэтому, чем ближе вы можете стать, так это с помощью блоков творческим образом. Люди предложили разные идеи, взгляните наlazylist а такжеVerstehen подходы, оба поддерживают вложенные понимания с условиями:

require 'lazylist'
list { [x, y] }.where(:x => [1, 2], :y => [3, 4]) { x+y>4 }.to_a
#=> [[1, 4], [2, 3], [2, 4]]

require 'verstehen'
list { [x, y] }.for(:x).in { [1, 2] }.for(:y).in { [3, 4] }.if { x+y>4 }.comprehend
#=> [[1, 4], [2, 3], [2, 4]]

Конечно, это не то, что вы называете идиоматическим Ruby, поэтому обычно безопаснее использовать типичныйproduct + select + map подход.

Понимание списка в Ruby предоставляет целый ряд различных способов сделать что-то вроде понимания списка в Ruby.

Ни один из них явно не описывает вложенные циклы, но, по крайней мере, некоторые из них могут быть вложены довольно легко.

Например, принятый ответ Роберта Гэмбла предлагает добавить метод Array # comprehend.

class Array
  def comprehend(&block)
    return self if block.nil?
    self.collect(&block).compact
  end
end

Сделав это, вы можете написать свой код как:

digits.comprehend{|d| chars.comprehend{|ch| d.to_s+ch if ch =='a'} if d>=2}

Сравните с кодом Python:

[str(d)+ch for d in digits for ch in chars if d >= 2 if ch == 'a']

Различия довольно незначительны:

The Ruby code is a bit longer. But that's mostly just the fact that "comprehend" is spelled out; you can always call it something shorter if you want. The Ruby code puts things in a different order—the arrays come at the beginning instead of in the middle. But if you think about it, that's exactly what you'd expect, and want, because of the "everything is a method" philosophy. The Ruby code requires nested braces for nested comprehensions. I can't think of an obvious way around this that doesn't make things worse (you don't want to call "[str,digits].comprehend2" or anything…).

Конечно, настоящая сила Python в том, что если вы решите, что хотите лениво вычислять список, вы можете преобразовать свое понимание в выражение генератора, просто удалив скобки (или превратив их в скобки, в зависимости от контекста). Но даже там вы можете создать Array # lazycomprehend или что-то в этом роде.

Ваш ответ на вопрос