I have a Scala app with a list of items with checkboxes so the user select some, and click a button to shift them one position up (left). I decided to write a function to sh
This is basically an imperative algorithm with a functional style.
def shifWithSwap[T](a: Array[T], p: T => Boolean) = {
def swap(i:Int, j:Int) = {
val tmp = a(i); a(i) = a(j); a(j) = tmp
}
def checkAndSwap(i:Int) = i match {
case n if n < a.length - 1 && !p(a(i)) && p(a(i+1)) => swap(i, i+1)
case _ =>
}
(0 until a.length - 1) map checkAndSwap
a
}
It modifies the Array in place, with a side effect. I think it really does it like the version in the question, except it's easier to read. Imperative does not have to be ugly...
Edit: darn, couldn't fall asleep until I wrote this down (same as above, just more compact):
def shift[T](a: Array[T], p: T => Boolean) = {
for (i <- 0 until a.length - 1; if !p(a(i)) && p(a(i+1))) {
val tmp = a(i); a(i) = a(i+1); a(i+1) = tmp // swap
}
a
}
Edit: this doesn't actually solve the posed problem--it solves a related but different problem (bumping up the priority of marked items by one). I'm leaving it here for reference, however.
Here's a "one-liner", using arrays as requested, for Scala 2.8.
def shiftUp[T](a: Array[T], p: T => Boolean) = {
a.zipWithIndex.map(ci => {
(ci._1 , if (p(ci._1)) ci._2 - 1.5 else ci._2.toDouble)
}).sortWith((l,r) => l._2 < r._2).map(_._1)
}
scala> shiftUp(Array('h','E','l','l','O'),(c:Char)=>c.isUpper).toArray
res0: Array[Char] = Array(E, h, l, O, l)
scala> shiftUp("HeLlO".toArray,(c:Char)=>c.isUpper).toArray
res1: Array[Char] = Array(H, L, e, O, l)
I leave it as an exercise to the reader to figure out how it works. (If you really want generics with T, in Scala 2.8 it's going to give you an GenericArray; you then can toArray it if you want a Java potentially-primitive array.)
I don't know enough to write it in Scala, but this problem is tailor-made for the list functions takeWhile
and dropWhile
. The idea is that you split the list of items into three parts:
Left part, computed with takeWhile
, contains leftmost elements not satisfying the predicate.
Middle part is the group of elements you want to shift left, computed by dropping the left elements and then takeWhile
the remainder.
Right part is everything left over; dropWhile
the middle elements.
Here it is in Haskell:
-- take first group of elements satisfying p and shift left one
shift :: (a -> Bool) -> [a] -> [a]
shift p l = case reverse left of
[] -> l
(a:as) -> reverse as ++ middle ++ a : shift p right
where left = takeWhile (not . p) l -- could be done with List.break
notLeft = dropWhile (not . p) l
middle = takeWhile p notLeft -- could be done with List.span
right = dropWhile p notLeft
And here's a single unit test:
*Shiftup> shift (>9) [1, 2, 3, 44, 55, 6, 7, 8]
[1,2,44,55,3,6,7,8]
Haskell programmers might use List.break
or List.span
to combine calls to takeWhile
and dropWhile
, but I'm not sure if Scala has these things. Besides, takeWhile
and dropWhile
are nice meaningful names, whereas I at least find break
and span
less perspicuous.
EDIT: fixed recursive call to do shift p right
instead of right
to shift up all groups.
Here's another variant on Geoff's answer:
def shift[T](l: List[T], p: T => Boolean): List[T] = {
l match {
case a::b::t if ! p(a) && p(b) => b::shift(a::t, p)
case a::t => a::shift(t, p)
case Nil => l
}
}
Quickly tested using
scala> def pred(c: Char) = c.isUpper
pred: (c: Char)Boolean
scala> shift("abcDEfghI".toList, pred)
res3: List[Char] = List(a, b, D, E, c, f, g, I, h)
scala> shift("AbCd".toList, pred)
res4: List[Char] = List(A, C, b, d)
scala> shift(Nil, pred)
res5: List[Nothing] = List()
Here's version two
def shift[T](l: List[T], p: T => Boolean, r: List[T] = Nil): List[T] = {
l match {
case a::b::t if ! p(a) && p(b) => shift(a::t, p, b::r)
case a::t => shift(t, p, a::r)
case Nil => r.reverse
}
}
A solution in J:
('abcdefghijklmnopqrstuvwxyz';'ABCDEFGHIJKLMNOPQRSTUVWXYZ') (4 : '(y#~y e. >1{x)([: I. '' ''= ])} }._1&|.&.((1,~y e. >0{x)&#)y,'' ''') 'abcDEfghI'
abDEcfgIh
Let’s break this into named pieces for easier comprehension. The final string “abDEcfgIh
” is the result of applying a function to the string “abcDEfghI
” which is the right argument to the function. The pair of alphabets constitute the left argument to the function (which is the part beginning “(4 :
…”). So, instead of the 2-element vector of boxed strings, we could name each one individually:
'lc uc'=. 'abcdefghijklmnopqrstuvwxyz';'ABCDEFGHIJKLMNOPQRSTUVWXYZ'
Now that we have two variables “lc
” and “uc
” for the lower-case and upper-case alphabets, let’s examine the body of the function in detail. Taking a logically coherent chunk from the right end, since this would be evaluated first, we could name this like so:
rmUCshift=: 4 : 0
}._1&|.&.((1,~y e. >0{x)&#)y,' '
)
This defines “rmUCshift
” as something that requires a right and left argument (the “4 :
” specifies this) with the body beginning on the next line and continuing to the bare closing paren. The “4 : 0
” form, followed by the body, is a variant of the “4 :
‘body’” form shown initially. This verb rmUCshift
can be invoked independently like this:
(lc;'') rmUCshift 'abcDEfghI' NB. Remove upper-case, shift, then insert
ab cfg h NB. spaces where the upper-case would now be.
The invocation is indented three spaces and the output immediately follows the it. The left argument (lc;'')
is a two-element vector with the empty array specified as the second element because it’s not used in this piece of the code – we could have used any value after the semicolon but the two single quotes are easy to type.
The next pieces to name are these (definitions followed by examples):
ixSpaces=: [:I.' '=]
ixSpaces 'ab cfg h'
2 3 7
onlyUC=: 4 : 'y#~y e.>1{x'
('';uc) onlyUC 'abcDEfghI'
DEI
Combining these named pieces together gives us this:
(lc;uc) (4 : '(x onlyUC y)(ixSpaces x rmUCshift y)}x rmUCshift y') 'abcDEfghI'
abDEcfgIh
However, the repetition of “x rmUCshift y
” is unnecessary and can be simplified to give us this:
(lc;uc) (4 : '(x onlyUC y) ((ixSpaces ]) } ]) x rmUCshift y') 'abcDEfghI'
abDEcfgIh
Not the fastest, but not limited to String and using the same logic as @oxbow_lakes
def shift[T](iter: Iterable[T])(p: T=>Boolean): Iterable[T] =
iter.foldLeft(Iterable[T]())((buf, elm) =>
if (p(elm) && buf.nonEmpty)
buf.dropRight(1) ++ Iterable[T](elm) ++ Iterable[T](buf.last)
else
buf++Iterable[T](elm)
)
def upperCase(c:Char)=c.isUpper
shift("abcDEfghI")(upperCase).mkString
//scala> res86: String = abDEcfgIh
val array="abcDEfghI".toArray
shift(array)(upperCase).toArray
//res89: Array[Char] = Array(a, b, D, E, c, f, g, I, h)
def pair(i:Int)=i%2==0
val l=List(1,2,3,5,4,6,7,9,8)
shift(l)(pair)
//scala> res88: Iterable[Int] = List(2, 1, 3, 4, 6, 5, 7, 8, 9)