объяснить одно выражение метода Ruby Array uniq - PullRequest
2 голосов
/ 14 октября 2011
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.

Ответы [ 3 ]

4 голосов
/ 14 октября 2011

Это немного сложно.

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

x в этом блоке - каждое значение в массиве. Вы определяете уникальность как «строка начинается с a?». Значение a является первым, которое оценивается как true, и, следовательно, является первым значением. b является первым, чтобы оценить как false, так и второе значение. И c, и d также оцениваются как 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". Weird!

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

Здесь вы определили класс персонажа. Вы определили уникальность с помощью «строк, содержащих a, b или c». a является первым, чтобы удовлетворить как true. d является единственным значением для оценки как false.

Надеюсь, это поможет.

0 голосов
/ 14 октября 2011

Посмотрите на это так: когда вы используете 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
0 голосов
/ 14 октября 2011

Определение уникальности основано на результате передачи каждого элемента в блок.

Так, например, первый представляет вопрос каждому элементу, являются ли они "a". Первый говорит «да», поэтому «а» считается уникальным. Второй говорит «нет», поэтому «б» считается уникальным. Другие также говорят «нет», поэтому они не считаются уникальными (поскольку ответ «нет» - это тот, который мы уже видели).

Однако то, что я не могу объяснить легко, это то, почему это работает для вас в Ruby 1.8.7; в 1.8.7 и до этого аргумент блока Array # uniq игнорировался. Эта функция была добавлена ​​в Ruby 1.9. Возможно, у вас есть исправленная версия?

...