List 如何在erlang中更改列表中的元素

List 如何在erlang中更改列表中的元素,list,erlang,element,edit,List,Erlang,Element,Edit,我有一个列表,我使用函数lists:nth()on返回某个索引处元素的值。有人知道如何编辑此值吗 任何帮助都会很好 谢谢 马克 编辑:这里有更多的信息。 假设我有一个列表L,它表示一行基于文本的网格 L = [H,H,H,H,H]. 我想访问一个指定的元素,比如说第三个元素,然后把它改为E。如果我再次使用列表L,它将是 [H,H,E,H,H] 我希望这更有意义 谢谢。列表是不可变的,因此不能“更改”列表中的项目。如果确实要替换给定位置的项目,则应将元素前的列表附加到(已更改)元素和剩余列表中:

我有一个列表,我使用函数lists:nth()on返回某个索引处元素的值。有人知道如何编辑此值吗

任何帮助都会很好

谢谢

马克

编辑:这里有更多的信息。 假设我有一个列表L,它表示一行基于文本的网格

L = [H,H,H,H,H].
我想访问一个指定的元素,比如说第三个元素,然后把它改为E。如果我再次使用列表L,它将是

[H,H,E,H,H]

我希望这更有意义


谢谢。

列表是不可变的,因此不能“更改”列表中的项目。如果确实要替换给定位置的项目,则应将元素前的列表附加到(已更改)元素和剩余列表中:

1> L=[1,2,3,4,5].
[1,2,3,4,5]
2> lists:sublist(L,2) ++ [lists:nth(3,L)*100] ++ lists:nthtail(3,L).
[1,2,300,4,5]

编辑:这个场景有点不寻常,不过。。。你手头有具体的问题吗?也许它可以更好地用列表来表达:map?

当使用列表时,所有元素通常具有相似的数据类型或含义。你很少看到像“约翰·多伊”、“1970-01-01”、“伦敦”这样的列表,而是
#person{name=“John Doe”,…}
甚至是{“约翰·多伊”,…}。要更改记录和元组中的值,请执行以下操作:

-record(person,{name,born,city}).
f(#person{}=P) -> P#person{city="New City"}. % record
f({_,_,_,}=Tuple) -> erlang:setelement(3,Tuple,"New City"). % tuple 
对于您的特定问题,这可能无法解决任何问题。以您自己的评论为例:

f1([H1,H2,_H3,H4,H5],E) -> [H1,H2,E,H4,H5]. 
如果您对环境和问题给出更具体的描述,那么就更容易确定哪种解决方案可能工作得最好

编辑:一个(相当糟糕的)解决方案1

replacenth(L,Index,NewValue) -> 
 {L1,[_|L2]} = lists:split(Index-1,L),
 L1++[NewValue|L2].

1> replacenth([1,2,3,4,5],3,foo).
[1,2,foo,4,5]
或者根据列表的长度稍微提高效率

replacenth(Index,Value,List) ->
 replacenth(Index-1,Value,List,[],0).

replacenth(ReplaceIndex,Value,[_|List],Acc,ReplaceIndex) ->
 lists:reverse(Acc)++[Value|List];
replacenth(ReplaceIndex,Value,[V|List],Acc,Index) ->
 replacenth(ReplaceIndex,Value,List,[V|Acc],Index+1).

我上面的函数f1更好,但可能,只是可能问题仍在上面讨论的位置,或者。

使用
列表中的函数时,可能会导致代码看起来更清晰,效率更低,因为要更改的元素之前的元素列表将被复制两次。自己编写函数更有效,因为您可能会在函数中使用
列表
来包装代码,所以我不觉得它会不那么清晰

代替@D.Nibon的代码,我将函数编写为:

%% setnth(Index, List, NewElement) -> List.

setnth(1, [_|Rest], New) -> [New|Rest];
setnth(I, [E|Rest], New) -> [E|setnth(I-1, Rest, New)].

%% Can add following caluse if you want to be kind and allow invalid indexes.
%% I wouldn't!
%% setnth(_, [], New) -> New.
论证顺序可以讨论;不幸的是,
列出
模块在这里没有帮助,因为它在模块内不一致。虽然这不是一个尾部递归函数,但我觉得它更清晰。此外,效率上的差异很小,或者根本不存在,所以我想澄清一下。有关此问题的更多信息,请参阅:


要获得更通用的函数而不仅仅是新值,您可以传递一个
fun
,该函数将使用旧值调用并返回新值。在图书馆里,我可能两样都有

L = [H,H,H,H,H].
我想访问一个指定的元素,比如说第三个元素,然后把它改为E。如果我再次使用列表L,它将是


成为一个挑剔的人。在Erlang中,数据是持久的和不可变的。一旦定义了
L=…
部分,
L
就一成不变了。从那以后你不能改变它。您可以创建一个新值并将其绑定到另一个变量,
L1
say,然后停止使用
L
。然后,垃圾收集器将快速对
L
进行短期工作,并回收所使用的内存

因此,说再次使用
L
更改其内容有些错误,因为这是不可能的

另一点值得一提的是,如果将列表当作数组使用,则可以使用数组(从
数组
模块)或dict(从
dict
模块)。它大大提高了您案例中的查找和更新速度。但是,如果您所做的最多的是遍历列表以处理所有元素,那么列表可能会是赢家

1> lists:reverse(element(2, lists:foldl(fun(E, {I, L}) -> {I + 1, [case I of 2 -> e; _ -> E end|L]} end, {0, []}, [h,h,h,h,h]))).

[h,h,e,h,h]

虽然不漂亮,但我敢打赌这是相当有效的。

如果您的列表是由元组组成的,您可以使用。

替换(列表、索引、元素)->
替换(列表,_Current=0,索引,元素,[])。
替换([],,,,,Acc)->列表:反向(Acc);
替换([[u H|T],当前,索引=当前,元素,附件)->
替换(T,当前+1,索引,元素,[元素| Acc]);
替换([H|T]、当前、索引、元素、附件)->
替换(T,电流+1,索引,元件[H | Acc])。

假设我有列表L=[H,H,H,H,H]。我想把第三个元素改成E.Index=3。列表:子列表(L,索引-1)+“E”++列表:第n个尾巴(索引,L)。我编辑了这个问题以提供更多细节。我希望这有帮助。谢谢你。我最近问了一个确切的问题:一个同样的选择是
fun(R,N,L)->案例列表:{F,[[u124; T]}->F++[R | T]end(e,3,[h,h,h,h,h,h])
,但是这些实现是高效的,除非列表非常小。哇,没有意识到列表:map/foldl与列表相比太慢了:拆分或甚至列表:reverseWelcome to SO!你能解释一下这对OP和未来的访客是如何起作用的吗?谢谢
1> lists:reverse(element(2, lists:foldl(fun(E, {I, L}) -> {I + 1, [case I of 2 -> e; _ -> E end|L]} end, {0, []}, [h,h,h,h,h]))).

[h,h,e,h,h]