2

I have a sequence in Ceylon and I want to make a new sequence with one of the elements replaced with something else according an index:

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

In Scala, this is called update.

drhagen
  • 8,331
  • 8
  • 53
  • 82

3 Answers3

5

There are several ways to solve this problem, and I do like the solution by Quintesse above, using Array. That is, perhaps, what I would do in practice. However, there is one possibly-important downside of the Array solution: it allocates memory twice.

So let me just suggest a couple of different options, for the sake of completeness:

Using stream operations

This works, but is a bit verbose:

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

Note that here we are using the lazy stream operations take(), skip(), chain() and follow() to create a lazy stream of elements, and then the sequence() operation to take a copy into a new sequence. It allocates just once, in the call to sequence().

Using patch()

This also works:

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

Note that if it's good enough to get back an immutable List, you could drop the call to sequence(), resulting in:

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

And in this case there's no allocation at all (except for one trivial instance of List.Patch).

See the docs for List.patch().

Community
  • 1
  • 1
Gavin King
  • 3,182
  • 1
  • 13
  • 11
  • 1
    patch! That's what I was looking for. I must have autocompleted every other word in English: replace, update, exchange, insert, put, ... – drhagen Jan 19 '16 at 13:22
  • 2
    Patch is a great word though, since it implies placing something on top of something else so it looks different, but is not changed under the patch. Those other words would have sounded like you changed the original list. – AxelW Jan 26 '16 at 14:30
3

You could do it with a comprehension:

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

Try online

Lucas Werkmeister
  • 2,584
  • 1
  • 17
  • 31
3

Another way would be to copy it to an Array, which is mutable, and then back:

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

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

[String*] newStrings = array.sequence();
Quintesse
  • 452
  • 2
  • 9