Reputation: 700
Let's say I have a Scala List of objects. Each object is a case class comprised of an integer index and a string.
case class Item(index: Integer, name: String)
I have this list populated with, say, five items. Each item has a numeric index and some value in the string.
List(Item(0, "foo"), Item(1, "bar"), Item(2, "baz"), Item(3, "foobie"), Item(4, "blech"))
I have decided that I'd like the Item in "slot 3" to be in "slot 1." So what I want to do is not only set the index of the item in slot 3 to be 1, but I also want to physically reorder the List as well by pushing everything down. In other words, "promote" an Item later-on in the list closer to the beginning. I would end up with:
List(Item(0, "foo"), Item(1, "foobie"), Item(2, "bar"), Item(3, "baz"), Item(4, "blech"))
Sure, I can do this with an array and a var in the usual ways, but if I want to use an immutable list and simply create a new one, is there a nice, functional syntax for map that might help me do this? Or is there some kind of functional way to do this properly?
Upvotes: 0
Views: 1583
Reputation: 41769
Well, here you go, although I don't like it much.
From your comment, the index values can have gaps and so are not the position in the list. So we can assume nothing much about them so this just extracts them (and the Strings), manipulates the list of Strings, then builds Items from the list of indexes and resultant list of Strings.
case class Item(index: Integer, name: String)
val xs = List(Item(0, "foo"), Item(1, "bar"), Item(2, "baz"), Item(3, "foobie"), Item(4, "blech"))
def move(xs: List[Item], src:Int, dst:Int) = {
val strings = xs.map(_.name)
val indices = xs.map(_.index)
val (prefix, d::rest) = strings splitAt(dst)
val (middle, s::suffix) = rest splitAt(src-dst-1)
(indices zip (prefix ++ List(s) ++ List(d) ++ middle ++ suffix))
map {case (i, s) => Item (i, s)}
}
move (xs, 3, 1)
//> res0: List[lists.lists2.Item] = List(Item(0,foo), Item(1,foobie),
Item(2,bar), Item(3,baz), Item(4,blech))
Upvotes: 2