изменить другой индекс списка внутри цикла - PullRequest
0 голосов
/ 20 декабря 2018

Для изменения того же индекса мы можем сделать

mylist = [1,2,3]    
Enum.map(mylist, fn x-> -x end) // [-1,-2,-3]

Как бы мы изменили другой индекс, например

 for (i = 0; i < mylist.length; i++) {
     mylist[i+1] = -mylist[i];
 }

Ответы [ 3 ]

0 голосов
/ 20 декабря 2018

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

Если, например, вы хотите сравнить элементы с близлежащими элементами, вы можете сжать список с его смещением:

iex> enum = 1..5
1..5
iex> stream = Stream.drop(enum, 1) # Enum.drop/2 would also work
#Stream<[enum: 1..5, funs: [#Function<48.15162342/1 in Stream.drop/2>]]>
iex> Enum.zip(enum, stream) # Stream.zip/2 works if you're going to iterate
[{1, 2}, {2, 3}, {3, 4}, {4, 5}]

Для вашего конкретного примера, где следующее значение является предыдущимзначение отрицается, вы можете создать бесконечный поток и взять то, что вам нужно:

iex> 1 |> Stream.iterate(&-/1) |> Enum.take(3)
[1, -1, 1]

Если вы хотите изменить только одно значение, вам придется создать новый список с изменением только нового значения( ПРИМЕЧАНИЕ это не тот способ, которым вы хотите сделать несколько обновлений):

iex> {previous, [current | next]} = Enum.split(1..5, 3)
{[1, 2, 3], [4, 5]}
iex> Enum.concat([previous, [current * 12], next])
[1, 2, 3, 48, 5]
0 голосов
/ 21 декабря 2018

Оба ответа здесь до сих пор используют помощники базовой библиотеки Elixir, такие как Enum.with_index/2, или Stream.iterate/2, или Enum.map/2.

. Я должен продемонстрировать базовый функциональный подход для изменения индекса соседей, как вваш пример псевдокода.Я буду реплицировать фрагмент, который не приводит к сбою виртуальной машины.

> mylist = [ 1, 2, 3 ]
> for (i = 1; i < mylist.length; i++) { mylist[i-1] = -mylist[i] }
> mylist
//⇒ [ -2, -3, 3 ]

В Elixir, используя рекурсию, это будет:

defmodule Neighbour do
  def map(list, acc \\ [])
  def map([_, next | rest], acc), do: map(rest, [-next | acc])
  def map([next], acc), do: Enum.reverse([next, -next | acc])
end

Neighbour.map([1, 2, 3])
#⇒ [-2, -3, 3]
0 голосов
/ 20 декабря 2018

Помня, что данные являются неизменными в Erlang, и, за исключением того, что не стоит связывать императивное программирование с функциональным программированием, мы могли бы сделать что-то вроде следующего:

new_list = Enum.map(Enum.with_index(list), fn {v,i} -> 
  ((Enum.at(list, i + 1) ||  0) - v) 
end)

Что приведет к [1, 1, -3] или другими словами:

  2 - 1 = 1 
  3 - 2 = 1
  0 - 3 = -3

Как уже указывали другие, это было бы неэффективным способом сделать это в силу сложности O (n) из Enum.at/2.

Более производительное и идиоматическое решение было бы:

iex(1)> list0 = [1,2,3]
[1, 2, 3]
iex(2)> sliced = Enum.slice(list, 1, 2)  
[2,3]
iex(3) list2 = List.duplicate(0, length(list0) - length(sliced))
[2, 3, 0]
iex(21)> Enum.map(Enum.zip(list, list2), fn({v1, v2}) -> v2 - v1 end)
[1, 1, -3]
...