# Extract subarray of elements that appear after the last occurrence of “4”

I am doing some challenges, and in one challenge given a non-empty array of int, I am to return a new array containing the elements from the original array that come after the last 4 in the original array. The original array will contain at least one 4.

E.g:

post4([2, 4, 1, 2]) → [1, 2]
post4([4, 1, 4, 2]) → [2]
post4([4, 4, 1, 2, 3]) → [1, 2, 3]

As such, I have written code that works but it is far too complicated and unprofessional, at least it feels this way.

public static int[] post4(int[] nums) {

int startPoint = nums.length - 1;
int[] newArray;
int amtOfElements = 0;
int stopIndex = 0;

for (int i = startPoint; i >= 0; i--) {

if (nums[i] == 4) {
stopIndex = i;
i = 0;
} else {
amtOfElements++;
}
}

newArray = new int[amtOfElements];

for (int i = 0, j = stopIndex; i < amtOfElements; i++, j++) {
newArray[i] = nums[j + 1];
}

return newArray;
}


As such, this looks nasty to me.
How can I shorten this to a single for-loop?

• Consider looping from the right hand side downward... and stopping when you run into a 4. – alzee Jan 20 '17 at 21:30
• @user3137702 Umm... for(int i = startPoint;i>=0; i--) – OneCricketeer Jan 20 '17 at 21:31
• My code already does that? – BodyBingers Jan 20 '17 at 21:31
• Personally, I would break instead of i=0; – OneCricketeer Jan 20 '17 at 21:31
• This code seems optimal runtime O(N). Optimal code isn't always short, nor do I think a single loop is possible (because you need to switch direction). – OneCricketeer Jan 20 '17 at 21:35

I would use this:

public int[] post4(int[] arr) {
for(int i = arr.length-1; i >= 0; --i) {
if(arr[i] == 4) {
return Arrays.copyOfRange(arr, i+1, arr.length);
}
}
return new int[0]; // or null
}


If you like streams and lambdas (and shorten your code to 0 for loops :), you may use this

public static int[] post4(int[] nums) {

int marker = 4;
return IntStream.range(0, nums.length) //iterate over the indexes to find the marker
.map(i -> nums.length - i - 1) //reverse the order to start from the back
.filter(i -> marker == nums[i]) //find the marker
.mapToObj(skip -> IntStream.of(nums).skip(skip+1).toArray()) //skip the first elements and the marker (+1)
.findFirst() //the new array
.orElse(nums); //the original array if there is no marker, or int[0]  - its not that clear from your question
}


(although it's actually not shorter than the shortest answer)

• while is the simplest way to shorten your code to zero for-loops :-) – Mike B. Jan 20 '17 at 23:20
• :) ... streams are good for avoiding any loops ;) – Gerald Mücke Jan 20 '17 at 23:28
• I see at least 4 loops, behind the stream methods... – Usagi Miyamoto Jan 21 '17 at 0:06
• of course there is, deep down in the reference pipeline, but it doesn't matter what's behind. there's tons of assembler behind that, but all the higher languages are there to avoid writing assembler. And at some other level, nobody really cares whether there are streams or loops behind post4() ;) – Gerald Mücke Jan 21 '17 at 0:14

Stack data structure based solution:

public int[] post4(int[] nums) {

Stack<Integer> stack = new Stack<>();
int i = nums.length - 1;

while (nums[i] != 4) {
}

int[] newArray = new int[stack.size()];
int j = 0;

while (!stack.isEmpty()) {
newArray[j++] = stack.pop();
}

return newArray;
}


Two very simple and elegant loops with minimum work with indexes.