2016-08-14 6 views
0

Есть следующий код, который должен выбрать любой другой символ строки и сделать новую строку из них:рубин значение Выбора выбрать метод, которые не соответствуют критериям

def bits(string) 
    string.chars.each_with_index.select {|m, index| m if index % 2 == 0}.join 
end 

Однако, выберите возвращает этот вывод с испытанием случай "привет":

"h0l2o4" 

При использовании карты вместо этого я получить желаемый результат:

"hlo" 

Есть ли причина, почему выбор не будет работать в этом случае? В каких сценариях лучше использовать карту над выбором и наоборот

ответ

0

Если вы используете Enumerable#map, вы вернете массив, содержащий один элемент для каждого символа в строке.

arr = "try this".each_char.map.with_index { |c,i| i.even? ? c : nil } 
    #=> ["t", nil, "y", nil, "t", nil, "i", nil] 

, который так же, как

arr = "try this".each_char.map.with_index { |c,i| c if i.even? } 
    #=> ["t", nil, "y", nil, "t", nil, "i", nil] 

Мой первоначальный ответ предложил использовать Array#compact для удаления nil сек до присоединения:

arr.compact.join 
    #=> "tyti" 

, но, как @npn заметки, compact не является необходимым потому что Array#join применяет NilClass.to_s к nil's, преобразуя их в пустую строку s. Ergo, вы можете просто написать

arr.join 
    #=> "tyti" 

Другой способ можно использовать map является первым применять Enumerable#each_cons передать пары символов, а затем возвращает первый символ каждой пары:

"try this".each_char.each_cons(2).map(&:first).join 
    #=> "tyti" 

Даже так, Array#select является предпочтительным, поскольку он возвращает только символы, представляющие интерес:

"try this".each_char.select.with_index { |c,i| i.even? }.join 
    #=> "tyti" 

вариант этого:

even = [true, false].cycle 
    #=> #<Enumerator: [true, false]:cycle> 
"try this".each_char.select { |c| even.next }.join 
    #=> "tyti" 

, который использует Array#cycle для создания нумератор и Enumerator#next генерировать свои элементы.

Одна маленькая вещь: String#each_char более эффективна с точки зрения памяти, чем String#chars, поскольку первая возвращает перечислитель, тогда как последняя создает временный массив.

В общем случае, когда приемник является массивом,

  • использования map когда вы хотите вернуть массив, содержащий один элемент для каждого элемента приемника.
  • использовать Enumerable#find, если вы хотите вернуть только один элемент приемника.
  • Array#select или Array#reject (или Enumerable#select или Enumerable#reject, если ресивер является перечислителем).

меня, я хотел бы использовать простое регулярное выражение:

"Now is the time to have fun.".scan(/(.)./).join 
    #=> "Nwi h iet aefn" 
+0

Не думаю, что на самом деле вам не нужно называть compact, чтобы удалить нуль из массива перед присоединением. #join, класс #to_s для каждого элемента, а у NilClass - метод to_s, который возвращает "". Поэтому я не думаю, что это так, чтобы полагаться на недокументированное поведение, чтобы пропустить вызов .compact. – nPn

+0

@nPn, спасибо за исправление. Я отредактировал. –

1

Если вы все еще хотите использовать select, попробуйте это.

irb(main):005:0> "hello".chars.select.with_index {|m, index| m if index % 2 == 0}.join 
=> "hlo" 

each_with_index не работает, потому что она выбирает как характер и индекс, а затем присоединиться все это.

0

Причина, по которой выбор не работает в этом случае, заключается в том, что select «Возвращает массив, содержащий все элементы перечисления, для которого данный блок возвращает истинное значение» (см. Документ here), так что вы получаете в своем случае представляет собой массив массивов [[h ', 0], [' l ', 2], [' o ', 4]], которые вы затем присоединяетесь для получения «h0l2o4».

Таким образом, select возвращает подмножество перечислимого. map возвращает одно к одному отображение предоставленного перечислимого. Например, следующее: «исправить» вашу проблему, используя карту, чтобы извлечь символ из каждого значения, возвращаемого select.

def bits(string) 
    string.chars.each_with_index.select {|m, index| m if index % 2 == 0}.map { |pair| pair.first }.join 
end 

puts(bits "hello") 
=> hlo 

По многим причинам это не лучший способ получить из строя любого другого персонажа.

Вот еще один пример использования карты. В этом случае каждый индекс сопоставляется либо символу, либо нулевому соединению.

def bits(string) 
    string.chars.each_index.map {|i| string[i] if i.even? }.join 
end 
Смежные вопросы