在循环内修改列表的其他索引

时间:2018-12-20 18:30:06

标签: arrays list loops elixir

要修改相同的索引,我们可以做

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 :(得分:1)

最重要的是要记住,您必须创建一个全新的列表,因此您应该考虑如何最好地获得所需的内容,而不是如何复制用另一种语言来处理它的方式。

例如,如果您想将项目与附近的项目进行比较,则可以使用偏移量压缩列表:

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]

答案 1 :(得分:1)

到目前为止,这里的两个答案都是使用Enum.with_index/2Stream.iterate/2Enum.map/2之类的Elixir核心库帮助程序。

我将展示伪指令示例中修改邻居索引的准系统功能方法。我将复制不会使VM崩溃的代码段。

> 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]

答案 2 :(得分:0)

请记住,数据在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

正如其他人指出的那样,按照Enum.at/2的O(n)复杂度,这样做将是一种低效的方法。

更高效,更惯用的解决方案是:

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]