2

I am doing the find the parity kata in Java. I am not sure why but my junit test fails as it returns -10 instead of 3 for part of the first test. If someone could please let me know as to why that is? The test fails at example test1 as it returns -10 instead of 3.

Update I amended my code(please see below) to do the following. So now it passes all the tests in eclipse but for some reason still fails in the code wars website. The error message is expected:<2> but was:<7>

import java.util.ArrayList;

public class FindOutlier {

    private ArrayList<Integer> odds = new ArrayList<Integer>();
    private ArrayList<Integer> evens = new ArrayList<Integer>();

    public static void main(String[] args) {

    }

    public int find(int[] integers) {
        int finalResult = 0;

        for (int i = 0; i < integers.length; i++) {
            if (integers[i] % 2 != 0) {
                odds.add(integers[i]);
            } else {
                evens.add(integers[i]);
            }
        }

        if (evens.size() > odds.size()) {
            finalResult += odds.get(odds.size()-1);

        } else {

            finalResult += evens.get(evens.size()-1);

        }

        return finalResult;

    }
}

and here is the jnuit test

package Tests;
import static org.junit.Assert.*;
import org.junit.Before;
import org.junit.Test;
import Supermarket_Pricing.FindOutlier;

public class OutlierTest{
    private FindOutlier foo;

@Before
public void setup(){
    foo = new FindOutlier();

}

 @Test
 public void testExample() {
     int[] exampleTest1 = {2,6,8,-10,3}; 
     int[] exampleTest2 = {206847684,1056521,7,17,1901,21104421,7,1,35521,1,7781}; 
     int[] exampleTest3 = {Integer.MAX_VALUE, 0, 1};
     assertEquals(3, foo.find(exampleTest1));
     assertEquals(206847684, foo.find(exampleTest2));
     assertEquals(0, foo.find(exampleTest3));
 }}
user6248190
  • 1,233
  • 2
  • 16
  • 31
  • 3
    by doing this : `odds = new ArrayList(Arrays.asList(integers[i]));` for odds and evens arent you overwriting or creating new objects every time – Shreyas Sarvothama Oct 19 '16 at 13:03
  • I think you're doing the kata wrong: Delete what you have so far. Start with the a test of the simples possible _behavior_. (e.g. a List with a single element as input). Then implement that behavior but nothing more. Then write _another test_ that requeres something a bit more complicated. Implement that and continue this way. – Timothy Truckle Oct 19 '16 at 13:13
  • 1
    BTW: this weekend is http://globalday.coderetreat.org/ find an event near to you to join in! – Timothy Truckle Oct 19 '16 at 13:15
  • @TimothyTruckle the test was the one available in code wars, it was already written – user6248190 Oct 19 '16 at 13:21
  • afair a coding kata is about to write code your own. I'm pretty sure you do not need practice in _copy/paste_... ;o) – Timothy Truckle Oct 19 '16 at 13:28

3 Answers3

4

Your algorithm is wrong: odds and evens do not represent lists of odd and even numbers; instead, they represent a single-element list containing the last odd or even value found.

When you run your program on the first example, odds is [3] and evens is [-10] (the last odd and the last even number, correspondingly). Your if condition is structured in such a way as to prefer evens to odds, explaining the return.

Since the problem is set in such a way that there is always only one outlier, you do not need additional collections at all. You can structure your algorithm in this way:

  • Take the first three numbers (the problem guarantees that there's going to be at least three)
  • Count the number of odds among the first three numbers
  • Count the number of evens among the first three numbers
  • If you have more odds than evens, then find and return the first even number
  • If you have more evens than odds, then find and return the first odd number

Here is a simple implementation:

int firstThreeParity = integers[0]%2 + integers[1]%2 + integers[2]%2;
int rem = firstThreeParity < 2 ? 1 : 0;
for (int i = 0; i < integers.length; i++) {
    if (integers[i] % 2 == rem) {
        return integers[i];
    }
}
return -1; // If the input is correct, we'll never reach this line
Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523
  • when you say take the first three numbers, do you mean through the for loop? – user6248190 Oct 19 '16 at 13:32
  • @user6248190 No, there will be no first or second loop - you will need only one loop in the whole program. Compute `integers[0]%2 + integers[1]%2 + integers[2]%2`. If it zero or one, look for the first odd number; otherwise, look for the first even number. – Sergey Kalinichenko Oct 19 '16 at 13:34
  • would you mind explaining what the variable rem is doing. what does firstThreeParity < 2 ? 1 : 0; mean? – user6248190 Oct 19 '16 at 13:41
  • @user6248190 The loop is looking for the first odd or for the first even number. An odd number has the remainder of `1` when you call `%2` on it; an even number has the remainder of `0`. Variable `rem` is set to the "target" remainder - zero when we search for an even number, or one when we search for an odd one. – Sergey Kalinichenko Oct 19 '16 at 13:53
  • sorry one more thing, would you mind explaining the syntax for rem? I have never comes across a question mark in java. I also thought the colon was only used for loops – user6248190 Oct 19 '16 at 14:24
  • @user6248190 That's a [ternary conditional operator](http://stackoverflow.com/q/798545/335858). – Sergey Kalinichenko Oct 19 '16 at 14:28
1

Here is the simplest method that I saw online:

int sum = Arrays.stream(integers).limit(3).map(i -> Math.abs(i) % 2).sum();
int mod = (sum == 0 || sum == 1) ? 1 : 0;

    
return Arrays.stream(integers).parallel().filter(n -> Math.abs(n) % 2 == mod).findFirst().getAsInt();
  1. Since we are warned the array may be very large, we should avoid counting values any more than we need to. We only need the first 3 integers to determine whether we are chasing odds or evens.

  2. So, take the first 3 integers and compute the value of Math.abs(i) % 2 on each of them.It will be 0 for even numbers and 1 for odd numbers.

  3. Now, add them. If sum is 0 or 1, then we are chasing odds. If sum is 2 or 3, then we are chasing evens.

Val
  • 11
  • 1
0

Try this in your for loop and it should work:

for (int i = 0; i < integers.length; i++) {
            if (integers[i] % 2 != 0) {
                odds.add(integers[i]);
            } else {
                evens.add(integers[i]);
            }
 }

Problem in your code was, every time you were creating a new instance of odd and even so only the last element was getting stored in odds and evens...