Я пытаюсь подсчитать, сколько раз число находится в каждом диапазоне от range1 до range4. Диапазон 1 - 1-10, диапазон 2 - 11-20, диапазон 3 - 21-30, а диапазон 4 - 31-40. Что у меня ниже:

range1=0
range2=0
range3=0
range4=0
arr=[1,11,2,22,33,23]
Enum.each arr, fn(x) ->
  if x >=1 and x<=10 do
    range1=range1+1
  end
  if x>=11 and x<=20 do
    range2=range2+1
  end
  if x>=21 and x<=30 do
    range3=range3+1
  end
  if x>=31 and x<=40 do
    range4=range4+1
  end
end 

IO.puts range1
IO.puts range2
IO.puts range3
IO.puts range4

Однако, когда я запустил его, он скажет, что все они 0. Почему он это делает?

0
user14566284 17 Мар 2021 в 06:17

2 ответа

Лучший ответ

- неизменяемый язык. Невозможно изменить значение переменной. Всегда.

Можно повторно привязать переменную, но она никогда не попадет во внешнюю область видимости, поэтому вы просто привязываете rangeN во внутренней области, чтобы немедленно ее отбросить. Переменная (имеющая такое же имя по совпадению) из внешней области никогда не изменяется.

У нас нет циклов в тоже. Вместо этого мы используем map / reduce.

При этом вам понадобится Enum.reduce/3.

Enum.reduce(
    [1,11,2,22,33,23], # input
    {0, 0, 0, 0},      # initial accumulator
    fn x, {acc1, acc2, acc3, acc4} ->
  cond do
    x>=1 and x<=10 -> {acc1 + 1, acc2, acc3, acc4}
    x>=11 and x<=20 -> {acc1, acc2 + 1, acc3, acc4}
    x>=21 and x<=30 -> {acc1, acc2, acc3 + 1, acc4}
    x>=31 and x<=40 -> {acc1, acc2, acc3, acc4 + 1}
  end
end)
#⇒ {2, 1, 2, 1}

Функция всегда возвращает результат последнего выражения, поэтому здесь мы должны использовать cond/1. Но идиоматическим способом было бы иметь несколько предложений функции накопления с охранниками.

Enum.reduce [1,11,2,22,33,23], {0, 0, 0, 0}, fn 
  x, {acc1, acc2, acc3, acc4} when x>=1 and x<=10 ->
    {acc1 + 1, acc2, acc3, acc4}
  x, {acc1, acc2, acc3, acc4} when x>=11 and x<=20 ->
    {acc1, acc2 + 1, acc3, acc4}
  x, {acc1, acc2, acc3, acc4} when x>=21 and x<=30 ->
    {acc1, acc2, acc3 + 1, acc4}
  x, {acc1, acc2, acc3, acc4} when x>=31 and x<=40 ->
    {acc1, acc2, acc3, acc4 + 1}
end 

Чтобы получить значения, можно либо сопоставить шаблон с результатом, либо использовать Kernel.elem/2 < / а>.

{less_that_10, _, _, _} =
  Enum.reduce(...)
less_than_10
#⇒ 2

input
|> Enum.reduce(...)
|> elem(0)
#⇒ 2
4
Aleksei Matiushkin 17 Мар 2021 в 13:59