Что делать, если я получаю предупреждение возможности кредо-рефакторинга, подобное приведенному ниже?
One `Enum.reject/2` is more efficient than `Enum.reject/2 |> Enum.reject/2`
Например, как я могу перекодировать следующую функцию, используя одинEnum.reject/2
вместо Enum.reject/2 |> Enum.reject/2
?
def my_reject_test() do
(1..10)
|> Enum.reject(&(rem(&1, 2) == 0))
|> Enum.reject(&(rem(&1, 3) == 0))
end
Простой способ сделать это:
(1..10)
|> Enum.reject(fn x -> rem(x, 2) == 0 || rem(x, 3) == 0 end)
|> IO.inspect()
Для более сложных сценариев я иногда использую Enum.reduce/3
или рассматриваю возможность добавления именованной частной функции для выполнения логики (для удобочитаемости).
Это хорошее напоминание о том, что просмотр списков может быть дорогостоящим (для длинных списков), поэтому, когда это возможно, вы должны свести к минимуму количество проходов по ним. Использование Enum.reject/2
дважды усложняет алгоритм O(2n), тогда как его использование только один раз сохраняет его сложность O(n).
Вы можете использовать or/2
, чтобы объединить условия:
iex> Enum.reject(1..10, &(rem(&1, 2) == 0 or rem(&1, 3) == 0))
[1, 5, 7]
Причина, по которой кредо указывает на это, заключается в том, что конвейерная обработка два Enum.reject/2
сначала создаст промежуточный список, а затем пройдёт его ещё раз:
iex> 1..10
1..10
iex> |> Enum.reject(&(rem(&1, 2) == 0))
[1, 3, 5, 7, 9]
iex> |> Enum.reject(&(rem(&1, 3) == 0))
[1, 5, 7]
Да, я больше не получаю предупреждения. Вы очень понятно и доступно написали. Большое спасибо Сабивара
Это круто. Вы написали очень хорошее логическое объяснение, также ссылаясь на сложность. Кроме того, как вы рекомендуете, идея преобразования
& Shorthand
вAnonymous Function
иногда кажется мне более понятной и читабельной. Большое спасибо за ваш ответ, Эверетт, он также решил мой вопрос.