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

时间:2011-01-23 19:45:22

标签: list erlang element edit

我有一个列表,我使用了函数列表:nth()on来返回某个索引处元素的值。有谁知道我怎么能编辑这个值?

任何帮助都会很棒

感谢

标记。

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

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

我想访问一个指定的元素,例如第三个,然后将其更改为E.然后,如果我再次使用列表L,那将是

[H,H,E,H,H]

我希望这更有意义。

谢谢。

7 个答案:

答案 0 :(得分:18)

列表是不可变的,因此您无法“更改”列表中的项目。如果你真的想要替换给定位置的项目,你应该在具有(更改的)元素和剩余列表的元素之前附加列表:

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]

编辑:情况有点不寻常,但是......你手头有特定的问题吗?也许它可以用例如表达更好列表:地图?

答案 1 :(得分:11)

虽然使用lists中的函数可能会导致代码看起来更清晰但效率较低,因为元素列表之前要更改的元素将被复制两次。自己编写函数效率更高,因为您可能会在函数中使用lists包装代码,但我觉得它不太清楚。

而不是@ 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.

可以讨论参数顺序;遗憾的是lists模块在​​这里没有帮助,因为它在模块中是不一致的。虽然这不是尾递归函数,但我觉得它更清晰。效率的差异很小或根本不存在,所以我会明确地说。有关此问题的详细信息,请参阅:

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

对于更通用的函数而不仅仅是新值,您可以传递fun,它将使用旧值调用并返回新值。在图书馆,我可能会同时拥有这两个。

答案 2 :(得分:3)

使用列表时,所有元素通常具有相似的数据类型或含义。您很少看到["John Doe","1970-01-01","London"]之类的列表,而是#person{name="John Doe",...}或甚至{“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更好,但也许,也许问题仍然如上所述或here

答案 3 :(得分:3)

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

我想访问一个指定的元素,例如第三个,然后将其更改为E.然后,如果我再次使用列表L,那将是

[H,H,E,H,H]

成为一个真正的挑剔者。在Erlang中,数据是持久性不可变。定义L = ...部分后,L就会一成不变。你无法从那里改变它。您可以做的是创建一个新值并将其绑定到另一个变量,L1然后停止使用L。然后,垃圾收集器将快速完成L的简短工作并回收它使用的内存。

因此,再次使用L更改其内容有点不对,因为这是不可能的。

值得一提的另一点是,如果您将列表视为数组,那么您可以使用数组(来自array模块)或使用dict(来自dict模块)。它极大地提高了您的查找和更新速度。如果您最常做的是遍历列表以处理所有元素,那么列表可能会成为赢家。

答案 4 :(得分:0)

如果您构建列表以使其由元组组成,则可以使用lists:keyreplace

答案 5 :(得分:0)

from kivy.app import App
from kivy.uix.recycleview import RecycleView
from kivy.uix.image import AsyncImage
from kivy.properties import StringProperty
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

LINK_HOLDER = ''


class WindowManager(ScreenManager):
    pass

class First(Screen):
    pass

class Second(Screen):
    rv_data = [{'text': 'random text here','source': LINK_HOLDER}]  # being assigned at run time ???

    '''
    links to use:
    https://www.dropbox.com/s/cku7lcyyikupyda/ruby.png?raw=1
    https://www.dropbox.com/s/nfkkt1b90p2g5qh/python.jpeg?raw=1
    https://www.dropbox.com/s/5840br37wwvymtr/julia.png?raw=1
    '''

class ImageAndTitle(BoxLayout):
    title = StringProperty()
    source = StringProperty()

class ExampleApp(App):

    def build(self):
        return load


load = Builder.load_string('''
WindowManager:
    First:
    Second:


<First>:
    name: 'first'
    FloatLayout:
        Button:
            text: 'Python'
            pos: 100, 300
            size_hint: None, None
            size: 100, 100
            on_press:
                global LINK_HOLDER
                LINK_HOLDER = 'https://www.dropbox.com/s/cku7lcyyikupyda/ruby.png?raw=1'
                app.root.current = 'second'
                root.manager.transition.direction = 'right'
        Button:
            text: 'Ruby'
            pos: 250, 300
            size_hint: None, None
            size: 100, 100
            on_press:
                global LINK_HOLDER
                LINK_HOLDER = 'https://www.dropbox.com/s/nfkkt1b90p2g5qh/python.jpeg?raw=1'
                app.root.current = 'second'
                root.manager.transition.direction = 'right'
        Button:
            text: 'Julia'
            pos: 450, 300
            size_hint: None, None
            size: 100, 100
            on_press:
                global LINK_HOLDER
                LINK_HOLDER = 'https://www.dropbox.com/s/5840br37wwvymtr/julia.png?raw=1'
                app.root.current = 'second'
                root.manager.transition.direction = 'right'

<ImageAndTitle>:
    Label:
        text: root.title
    AsyncImage:
        source: root.source

<Second>:
    name: 'second'
    GridLayout:
        cols: 2
        rows: 1
        BoxLayout:
            orientation: 'vertical'
            RecycleView:
                viewclass: 'ImageAndTitle'
                data: root.rv_data
                RecycleBoxLayout:
                    default_size_hint: 1, None
                    default_size: 100, 30
                    size_hint_y: None
                    height: self.minimum_height
                    orientation: 'vertical'

        BoxLayout:
            orientation: 'vertical'
            Label:
                text: 'five'
            Label:
                text: 'six'

''')


if __name__ == '__main__':
    ExampleApp().run()

答案 6 :(得分:-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]

不漂亮,但我打赌效率​​很高。