How would be a functional approach to shifting certain array elements?

后端 未结 9 2058
感动是毒
感动是毒 2021-01-05 07:03

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

9条回答
  •  孤街浪徒
    2021-01-05 07:36

    I don't claim this stuff below to be efficient or readable. Unfortunately, all the good answers seem to be taken, so I'm going for originality. :-)

    def shift[T](a: Seq[T], p: T => Boolean) = {
      val (areP, notP) = a.zipWithIndex partition { case (t, index) => p(t) }
      val shifted = areP map { case (t, index) => (t, index - 1) }
      val others = notP map (shifted.foldLeft(_){
        case ((t, indexNotP), (_, indexIsP)) => 
          if (indexNotP == indexIsP) (t, indexNotP + 1) else (t, indexNotP)
      })
      (shifted ++ others).sortBy(_._2).map(_._1)
    }
    

    So, here's what's happening. First, I associate each character with its index (a.zipWithIndex), and then separate then into areP and notP depending on whether the character satisfies p or not.

    So, at this point, I have two sequences, each composed of a character and its index in the original sequence.

    Next, I simply shift the index of the elements in the first sequence, by subtracting 1, and compute shifted.

    Computing the new index of the unshifted elements is much harder. For each of those elements (notP map), I'll do a foldLeft. The accumulator of the fold left will be the element itself (always with its index). The sequence that is being folded is the sequence of shifted elements -- so one can see that for each unshifted element, I traverse the whole sequence of shifted elements (highly inefficient!).

    So, we compare the index of the unshifted element to the index of each shifted element. If they are equal, increase the index of the unshifted element. Because the sequence of shifted elements is ordered (partition doesn't change the order), we know that we'll test first for lower indices, and then for higher indices, guaranteeing that an element will have its index increased as much as necessary.

    With that, we join the two sequences, order them by their new indices, and then map back to the element.

提交回复
热议问题