更新不可变序列

drh*_*gen 2 ceylon

我在锡兰有一个序列,我想创建一个新的序列,其中一个元素根据索引替换为其他元素:

[String*] strings = ["zero", "one", "two"];
value index = 1;
value newElement= "uno";
[String*]? newStrings = ???; // should be ["zero", "uno", "two"]
Run Code Online (Sandbox Code Playgroud)

在Scala中,这称为update.

Gav*_*ing 5

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

因此,为了完整起见,我只想提出几个不同的选择:

使用流操作

这有效,但有点冗长:

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

请注意,这里我们使用的是懒惰的流操作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();
Run Code Online (Sandbox Code Playgroud)

请注意,如果它足以返回不可变的List,您可以放弃调用sequence(),从而导致:

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

在这种情况下,根本没有分配(除了一个简单的实例List.Patch).

请参阅文档List.patch().

  • Patch是一个很好的词,因为它意味着把东西放在其他东西之上,所以它看起来不同,但在补丁下没有改变.那些其他的话听起来就像是你改变了原来的清单. (2认同)