更新不可变序列

Updating an immutable sequence

我在 Ceylon 有一个序列,我想制作一个新序列,根据索引将其中一个元素替换为其他元素:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";
[String*]? newStrings = ???; // should be ["zero", "uno", "two"]

在 Scala 中,这称为 update

你可以理解一下:

[String*] newStrings = [for (i->e in strings.indexed) i==index then newElement else e];

Try online

另一种方法是将它复制到一个数组,可变的,然后返回:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";

value array = Array(strings);
array.set(index, newElement);

[String*] newStrings = array.sequence();

有几种方法可以解决这个问题,我喜欢上面Quintesse的解决方案,使用Array。这也许就是我在实践中会做的事情。但是,Array 解决方案有一个 possibly-important 缺点:它分配内存 两次

为了完整起见,让我提出几个不同的选择:

使用流操作

这有效,但有点冗长:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";
[String*] newStrings = 
    strings.take(index)
           .chain(strings.skip(index+1).follow(newElement))
           .sequence();

请注意,这里我们使用惰性流操作 take()skip()chain()follow() 来创建元素的惰性流,然后 sequence() 操作将副本复制到新的序列中。它只分配一次,在对 sequence().

的调用中

使用patch()

这也有效:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";
[String*] newStrings = 
        strings.patch([newElement], index, 1)
               .sequence();

请注意,如果它足以取回不可变的 List,您可以放弃对 sequence() 的调用,结果是:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";
[String*] newStrings = 
        strings.patch([newElement], index, 1);

在这种情况下根本没有分配(除了 List.Patch 的一个微不足道的实例)。

参见docs for List.patch()