Challenge Five 2: Electric Boogaloo
Alright. Time to take another crack at this problem.
After some reflection I really think my logic was sound I just failed in my implementation. The problem has a few parts and I can break it down into smaller pieces and test the individual pieces. I also want to make the problem less complex, by removing the reversal part. I think that was just causing extra confusion.
Logic
// Step Zero: covert Int into StringArray
// Step One: determine swap one value and index
// Step Two: determine swap two value and index
// Step Three: make swap
// Step Four: split array on swap position: hold and reOrder
// Step Five: reorder the reOrder array from largest to smallest
// Step Six: rebuild the array & return
Step Zero
No tests necessary because I’m just using built in methods.
Implementation
// Step Zero: convert Int into StringArray
val numAsStringArray = theInt.toString.split("")
Step One
Logic
// Step One: determine swap one value and index
Tests
describe("Testing determineSwapOneValueAndIndex") {
it("should work for 54998") {
assert(StretchProblems.determineSwapOneValueAndIndex(54998.toString.split("")) === (4, 1))
}
it("should work for 45071") {
assert(StretchProblems.determineSwapOneValueAndIndex(45071.toString.split("")) === (0, 2))
}
it("should work for 31233") {
assert(StretchProblems.determineSwapOneValueAndIndex(31233.toString.split("")) === (2, 2))
}
it("should work for 22437") {
assert(StretchProblems.determineSwapOneValueAndIndex(22437.toString.split("")) === (3, 3))
}
it("should work for straightforward examples") {
assert(StretchProblems.determineSwapOneValueAndIndex(12.toString.split("")) === (1, 0))
assert(StretchProblems.determineSwapOneValueAndIndex(123.toString.split("")) === (2, 1))
assert(StretchProblems.determineSwapOneValueAndIndex(67809.toString.split("")) === (0, 3))
}
it("should return -1 for straightforward examples") {
assert(StretchProblems.determineSwapOneValueAndIndex(21.toString.split("")) === (-1, -1))
assert(StretchProblems.determineSwapOneValueAndIndex(54321.toString.split("")) === (-1, -1))
}
}
Implementation
def determineSwapOneValueAndIndex(numStringArray: Array[String]): (Int, Int) = {
var theValue = -1
var theIndex = -1
var i = numStringArray.length - 2
var notIdentified = true
while (i >= 0 && notIdentified) {
if (numStringArray(i + 1).toInt > numStringArray(i).toInt) {
theValue = numStringArray(i).toInt
theIndex = i
notIdentified = false
}
i -= 1
}
(theValue, theIndex)
}
Result: PASS
Step Two
This could be combined with the Step One, but I’m trying to hunt down my issue from earlier so I’m going the extra mile. This is something that I would likely refactor later.
Logic
// Step Two: determine swap two value and index
Tests
describe("Testing determineSwapTwoValueAndIndex") {
it("should work for 54998") {
assert(StretchProblems.determineSwapTwoValueAndIndex(54998.toString.split("")) === (8, 4))
}
it("should work for 45071") {
assert(StretchProblems.determineSwapTwoValueAndIndex(45071.toString.split("")) === (1, 4))
}
it("should work for 31233") {
assert(StretchProblems.determineSwapTwoValueAndIndex(31233.toString.split("")) === (3, 3))
}
it("should work for 22437") {
assert(StretchProblems.determineSwapTwoValueAndIndex(22437.toString.split("")) === (7, 4))
}
it("should work for straightforward examples") {
assert(StretchProblems.determineSwapTwoValueAndIndex(12.toString.split("")) === (2, 1))
assert(StretchProblems.determineSwapTwoValueAndIndex(123.toString.split("")) === (3, 2))
assert(StretchProblems.determineSwapTwoValueAndIndex(67809.toString.split("")) === (9, 4))
}
it("should return -1 for straightforward examples") {
assert(StretchProblems.determineSwapOneValueAndIndex(21.toString.split("")) === (-1, -1))
assert(StretchProblems.determineSwapOneValueAndIndex(54321.toString.split("")) === (-1, -1))
}
}
Implementation
def determineSwapTwoValueAndIndex(numStringArray: Array[String]): (Int, Int) = {
// find initial swap two value and index
var swapOneValue = -1
var swapOneIndex = -1
var theValue = -1
var theIndex = -1
var i = numStringArray.length - 2
var notIdentified = true
while (i >= 0 && notIdentified) {
if (numStringArray(i + 1).toInt > numStringArray(i).toInt) {
theValue = numStringArray(i + 1).toInt
theIndex = i + 1
swapOneValue = numStringArray(i).toInt
swapOneIndex = i
notIdentified = false
}
i -= 1
}
if (theIndex == -1) {
return (-1, -1)
}
// check that there aren't any better swap two candidates in the numbers after swapTwo position
i = theIndex;
while (i < numStringArray.length) {
if(numStringArray(i).toInt > swapOneValue && numStringArray(i).toInt < theValue) {
theValue = numStringArray(i).toInt
theIndex = i
}
i += 1
}
(theValue, theIndex)
}
After working on the implementation I realized that I couldn’t perform the check for a better swap two candidate, without also knowing the swap one value…
This caused me to essentially duplicate the the solution for Step One I performed earlier. Again showing that these should be collapsed into one solution, but before any refactoring can happen. I need ot make sure the implementation passes the tests.
Result: PASS
I will refactor. But let’s keep moving forward for now.
Step Three
Logic
// Step Three: make swap
Tests
describe("Testing swapValuesByIndex") {
it("should work for 54998") {
assert(StretchProblems.swapValuesByIndex(1, 4, 54998.toString.split("")) === 58994.toString.split(""))
}
it("should work for 45071") {
assert(StretchProblems.swapValuesByIndex(2, 4, 45071.toString.split("")) === 45170.toString.split(""))
}
it("should work for 31233") {
assert(StretchProblems.swapValuesByIndex(2, 3, 31233.toString.split("")) === 31323.toString.split(""))
}
it("should work for 22437") {
assert(StretchProblems.swapValuesByIndex(4, 3, 22437.toString.split("")) === 22473.toString.split(""))
}
}
Implementation
def swapValuesByIndex(indexOne: Int, indexTwo: Int, numStringArray: Array[String]): Array[String] = {
val tempVal = numStringArray(indexOne)
numStringArray(indexOne) = numStringArray(indexTwo)
numStringArray(indexTwo) = tempVal
numStringArray
}
Result: PASS
Step Four
Logic
// Step Four: split array on swap position: hold and reOrder
Tests
describe("Testing splitAndReorder") {
it("should work for 54998") {
assert(StretchProblems.splitAndReorder(1, 58994.toString.split("")) === 58499.toString.split(""))
}
it("should work for 45071") {
assert(StretchProblems.splitAndReorder(2, 45170.toString.split("")) === 45107.toString.split(""))
}
it("should work for 31233") {
assert(StretchProblems.splitAndReorder(2, 31323.toString.split("")) === 31323.toString.split(""))
}
it("should work for 22437") {
assert(StretchProblems.splitAndReorder(4, 22473.toString.split("")) === 22473.toString.split(""))
}
}
Implementation
def splitAndReorder(indexOne: Int, numStringArray: Array[String]): Array[String] = {
val (hold, reorder) = numStringArray.splitAt(indexOne + 1)
val reordered = reorder.sorted
hold ++ reordered
}
Without checking the documentation I made an assumption about .splitAt()
thinking it would split inclusively on the first group. Turns out is splits inclusively on the second group. So simply adding 1 to the parameter fixed the issue. Confirmed by the Scala Docs
Result: PASS
Step Five
Accomplished by previous step.
Step Six
Accomplished by previous step.
Bringing it together
I should be able to put all the pieces together in the original method and run it against the tests.
Implementation
def getNextBiggestNumber(theInt: Integer): Int = {
// I think breaking the problem down into smaller functions (that are tested) will help tremendously
// Step Zero: covert Int into StringArray
val numAsStringArray = theInt.toString.split("")
// Step One: determine swap one value and index
val (swapOneValue, swapOneIndex) = determineSwapOneValueAndIndex(numAsStringArray)
// return -1 if no swap candidate found
if (swapOneIndex == -1) {
return -1
}
// Step Two: determine swap two value and index
val (swapTwoValue, swapTwoIndex) = determineSwapTwoValueAndIndex(numAsStringArray)
// Step Three: make swap
val newArray = swapValuesByIndex(swapOneIndex, swapTwoIndex, numAsStringArray)
// Step Four: split array on swap position: hold and reOrder
val finalArray = splitAndReorder(swapOneIndex, numAsStringArray)
// Rebuild the array & return
finalArray.mkString.toInt
}
Results: PASS
Finally!
The solution is a little messy. I’d like to combine determineSwapOneValueAndIndex()
and determineSwapTwoValueAndIndex()
to reduce the duplication and remove the never used variable swapOneValue
, but overall I’m happy with the solution.
I’ll refactor at a later date.