Есть ли в Ruby метод Array, который объединяет «select» и «map»? - PullRequest
85 голосов
/ 30 июля 2010

У меня есть массив Ruby, содержащий некоторые строковые значения. Мне нужно:

  1. Найти все элементы, которые соответствуют некоторому предикату
  2. Запустить соответствующие элементы через преобразование
  3. Вернуть результаты в виде массива

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

def example
  matchingLines = @lines.select{ |line| ... }
  results = matchingLines.map{ |line| ... }
  return results.uniq.sort
end

Существует ли метод Array или Enumerable, который объединяет select и map в один логический оператор?

Ответы [ 14 ]

1 голос
/ 30 июля 2010
def example
  @lines.select {|line| ... }.map {|line| ... }.uniq.sort
end

В Ruby 1.9 и 1.8.7 вы можете также связывать и связывать итераторы, просто не передавая им блок:

enum.select.map {|bla| ... }

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

enum.inject.with_index {|(acc, el), idx| ... }

AFAICS, лучшее, что вы можете сделать, это первый пример.

Вот небольшой пример:

%w[a b 1 2 c d].map.select {|e| if /[0-9]/ =~ e then false else e.upcase end }
# => ["a", "b", "c", "d"]

%w[a b 1 2 c d].select.map {|e| if /[0-9]/ =~ e then false else e.upcase end }
# => ["A", "B", false, false, "C", "D"]

Но то, что вы действительно хотите, это ["A", "B", "C", "D"].

0 голосов
/ 26 февраля 2018

Ваша версия:

def example
  matchingLines = @lines.select{ |line| ... }
  results = matchingLines.map{ |line| ... }
  return results.uniq.sort
end

Моя версия:

def example
  results = {}
  @lines.each{ |line| results[line] = true if ... }
  return results.keys.sort
end

Это выполнит 1 итерацию (кроме сортировки) и имеет дополнительный бонус сохранения уникальности (если вас не интересует uniq, просто сделайте результаты массивом и results.push(line) if ...

0 голосов
/ 11 октября 2017

Если вы не хотите создавать два разных массива, вы можете использовать compact!, но будьте осторожны.

array = [1,1,1,2,3,4]
new_array = map{|n| n*3 if n==1}
new_array.compact!

Интересно, что compact! делает удаление на месте нуля. Возвращаемое значение compact! - это тот же массив, если были изменения, но nil, если не было nils.

array = [1,1,1,2,3,4]
new_array = map{|n| n*3 if n==1}.tap { |array| array.compact! }

Будет один лайнер.

0 голосов
/ 08 марта 2016

Вот пример. Это не то же самое, что ваша проблема, но может быть тем, что вы хотите, или может дать подсказку к вашему решению:

def example
  lines.each do |x|
    new_value = do_transform(x)
    if new_value == some_thing
      return new_value    # here jump out example method directly.
    else
      next                # continue next iterate.
    end
  end
end
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...