2011-01-23 13 views
9

Tengo una lista que he usado las listas de funciones: nth() on para devolver el valor de un elemento en un índice determinado. ¿Alguien sabe cómo puedo editar este valor?Cómo cambiar un elemento en una lista en erlang

cualquier ayuda sería grande

gracias

Marcos.

EDITAR: Aquí hay un poco más de información. decir que tenía una lista L que representa una línea de una red basada en texto

L = [H,H,H,H,H]. 

Y quiero tener acceso a un elemento especificado decir, por ejemplo, el tercero y el cambio a E. A continuación, si yo iba a utilizar el lista L de nuevo, sería

[H,H,E,H,H]

Espero que esto tiene más sentido.

Gracias.

+0

Hice esta pregunta recientemente: http://stackoverflow.com/questions/4370756/replace-an-element-at-an-index-in-a-list-in-erlang – MatthewToday

Respuesta

17

Una lista es inmutable, por lo que no puede "cambiar" un elemento de una lista. Si realmente desea reemplazar un elemento en una posición dada, se debe anexar la lista antes de que el elemento con el elemento (cambiado) y la lista restante:

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] 

EDIT: El escenario es un poco inusual, sin embargo. .. ¿Tienes un problema específico a mano? Tal vez se pueda expresar mejor con, por ejemplo, una lista: ¿mapa?

+0

dice que tenía la lista L = [H, H, H, H, H]. y quería cambiar el tercer elemento a E. – MulletDevil

+2

Índice = 3. listas: sublista (L, índice-1) ++ listas "E" ++: nthtail (índice, L). –

3

Al trabajar con listas, todos los elementos son a menudo de tipo de datos o significado similar. Rara vez ves listas como ["John Doe","1970-01-01","London"], sino #person{name="John Doe",...} o incluso {"John Doe", ...}. Para cambiar un valor en un registro y tupla:

Esto podría no resolver nada para su problema particular. Para tomar su propio ejemplo en el comentario:

f1([H1,H2,_H3,H4,H5],E) -> [H1,H2,E,H4,H5]. 

Si usted le da una descripción más específica del medio ambiente y el problema de que es más fácil en virtud del cual la solución podría funcionar mejor.

Editar: Un (bastante malo) Solución 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] 

o ligeramente más eficiente en función de la longitud de sus listas.

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). 

Aún mejor es mi función f1 anterior, pero tal vez, sólo tal vez el problema se encuentra todavía como se discutió anteriormente o here.

+0

Edité la pregunta para proporcionar más detalles. Espero que esto ayude. Gracias. – MulletDevil

11

Durante el uso de funciones de lists puede resultar en código que parece más claro es menos eficiente ya que la lista de elementos antes el elemento que desea cambiar se copiará dos veces. Es más eficiente escribir la función usted mismo, y como probablemente envuelva el código usando lists en una función, no creo que sea menos claro.

En lugar del código de @D.Nibon escribiría la función como:

%% 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. 

Se puede discutir el orden de los argumentos; desafortunadamente el módulo lists no es de ayuda aquí ya que es inconsistente dentro del módulo. Si bien esta no es una función recursiva de cola, creo que es más clara. Además, la diferencia de eficiencia es pequeña o inexistente, así que iría con claridad. Para obtener más información sobre este tema, véase:

http://www.erlang.org/doc/efficiency_guide/myths.html#tail_recursive
http://www.erlang.org/doc/efficiency_guide/listHandling.html#id64759

para una función más versátil en lugar de sólo el nuevo valor se podía pasar una fun que se llama con el valor antiguo y devolver el nuevo valor. En una biblioteca probablemente tendría los dos.

3
L = [H,H,H,H,H]. 

Y quiero acceder a un elemento especificado decir, por ejemplo, el tercero y el cambio a E. A continuación, si yo iba a utilizar la lista L de nuevo, sería

[H,H,E,H,H] 

Para ser un real nitpicker. En Erlang, los datos son persistentes y inmutables. Una vez que defina la pieza L = ..., el L está grabado en piedra. No puedes cambiarlo de allí en adelante. Lo que puede hacer es crear un nuevo valor y vincularlo a otra variable, L1 decir y luego dejar de usar L. El recolector de basura rápidamente realizará un breve trabajo de L y reciclará la memoria que usó.

Por lo tanto, es un poco incorrecto decir que al usar L otra vez cambia su contenido, ya que eso es imposible.

Otro punto que vale la pena mencionar es que si usa la lista como si fuera una matriz, puede usar una matriz (desde el módulo array) o usar un dict (desde el módulo dict). Mejora en gran medida la velocidad de las búsquedas y actualizaciones en su caso. Sin embargo, si lo que hace es atravesar la lista para procesar todos los elementos, la lista probablemente sea la ganadora.

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

No es bonito pero apuesto a que es bastante eficiente.

+0

Una alternativa en la misma línea es 'divertido (R, N, L) -> listas de casos: división (N-1, L) de {F, [_ | T]} -> F ++ [R | T] end end (e, 3, [h, h, h, h, h]) ', pero eficientes, estas implementaciones no lo son, a menos que la lista sea bastante pequeña. –

+0

Guau, no se dio cuenta de las listas: map/foldl son taaaan lentas comparando con las listas: dividir o incluso listas: inversa –

Cuestiones relacionadas