Как заменить элементы в массиве в elixir

#elixir

Вопрос:

Я хочу заменить все вхождения 2 на 3.Я хочу сделать это без использования значения индекса, потому что это было бы жестким кодированием. То, что у меня есть до сих пор, — это:

 
list=[1,2,3,4,2,34,2]

replace_at(list, index, value)

Enum.each list, fn(x) ->
if x==2 do
  replace_at(list, index, 3)
end

Enum.each list, fn(x) ->
IO.puts x
end

 

Ответ №1:

В Elixir у вас нет массивов, но есть связанный список. Если вы просто хотите заменить все значения 2 на 3, вы можете использовать функцию карты Enum модуля, как это:

 iex(1)> Enum.map(list, fn x -> if x == 2, do: 3, else: x end)
[1, 3, 3, 4, 3, 34, 3]
 

Вы также можете использовать сопоставление шаблонов:

 iex(1)> Enum.map(list, fn
...(1)> 2 -> 3
...(1)> x -> x
...(1)> end)
 

Комментарии:

1. Вы можете даже однострочно: Enum.map(list, fn 2 -> 3; x -> x end) (но ненадолго, так как форматер по умолчанию преобразует его в многострочный, если вы его используете).

Ответ №2:

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

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

 iex(2)> [1, 2, 3, 4, 2, 34, 2] |> Enum.map(fn
...(2)>   2 -> 3
...(2)>   other -> other
...(2)> end)
[1, 3, 3, 4, 3, 34, 3]
 

Метод с такой реализацией может быть похож на приведенный ниже код:

 defmodule Replace do

  def replace_all(list, from, to) do
    list
    |> Enum.map(fn
      ^from -> to
      other -> other
    end)
  end

end
 

Ответ №3:

У нас нет массивов, и доступ по индексу обходится дорого.

Если вы все еще хотите этого добиться, Enum.with_index/2 это ваш друг.

 replace_at = fn list, index, value -> 
  list
  |> Enum.with_index()
  |> Enum.map(fn
    {_, ^index} -> value # match index
    {value, _} -> value  # anything else   
  end)
end
 

И используйте его, как

 # index      0  1  2  3  4  5   6  
replace_at.([1, 2, 3, 4, 2, 34, 2], 2, 42)
#⇒ [1, 2, 42, 4, 2, 34, 2]
 

Замена всех 2 не имеет ничего общего с индексом, для этого не нужен индекс. Просто используйте Enum.map/2 из коробки.


Кроме того, вы должны усвоить, что Enum.each/2 это никогда ничего не меняет.

Комментарии:

1. Re: replace_at: List.replace_at/3 сделал бы то же самое из коробки и, я полагаю, был бы более эффективным, поскольку он должен иметь возможность повторно использовать правую часть списка и не должен проходить весь список (но это все равно дорого и не эквивалентно массиву).

2. Цель этого ответа состояла в основном в том, чтобы показать, как мы работаем с индексами в списках, если это необходимо. Enum.reduce_while/3 вместо Enum.map/2 этого и мы приступим к List.replace_at/3 реализации. Кроме того, put_in/3 Access.at/2 .