3

I am trying to solve a problem on CodeWars that has me finding the smallest number in an array. Here is my current code:

public class SmallestIntegerFinder {
public int findSmallestInt(int[] args){
    int smallest = args[0];
    for(int i=1; i < args.length; ++i){
        if(args[i] < args[0]){
            smallest = args[i];
        }
    }
    return smallest;
 }
}

Why doesn't this work? But when I change args[0] in the if statement to the variable smallest it works. What's the difference between the two? They both point to args[0] don't they?

public class SmallestIntegerFinder {
public int findSmallestInt(int[] args){
    int smallest = args[0];
    for(int i=1; i < args.length; ++i){
        if(args[i] < smallest){
            smallest = args[i];
        }
    }
    return smallest;
 }
}

The test array i'm using is: {78,56,232,12,11,43}

10 Answers10

6

Because args[0] is the first element in the array, while smallest starts with the first element; it updates to the next smallest value (consider 3, 1, 2; 2 is smaller than 3 but 1 is smaller than 2). You could also use Math.min(int, int) like

public int findSmallestInt(int[] args) {
    int smallest = args[0];
    for (int i = 1; i < args.length; ++i) {
        smallest = Math.min(smallest, args[i]);
    }
    return smallest;
}
Elliott Frisch
  • 198,278
  • 20
  • 158
  • 249
3

Smallest gets assigned the value that was in args[0], it's not a pointer to that memory location. Changing smallest does not change args[0]. So in your loop you are always comparing to args[0] instead of the lowest value you have seen so far.

rjdevereux
  • 1,842
  • 2
  • 21
  • 35
2

Its not the same,

  1. In the first case, you are putting the smallest as args[i], but again comparing with args[0]. So the base value for comparision is never updating.

  2. In the second case, your base value is being updated to the current smallest value and you are comparing with that, and so you get the overall least value.

user2195058
  • 887
  • 7
  • 10
2

Using .

public static int findSmallestInt(int[] args){
    return IntStream.of(args)
                    .min()
                    .getAsInt();
}

OR

public static int findSmallestInt(int[] args){
    return IntStream.of(args)
                    .min()
                    .orElseThrow(IllegalArgumentException::new);
}
Yassin Hajaj
  • 21,337
  • 9
  • 51
  • 89
  • out of curiosity : in what condition will IllegalArgumentException could be thrown ? – LeTex Apr 04 '16 at 20:19
  • 2
    `getAsInt()` will throw `NoSuchElementException` when `args` is empty, similar to your original code throwing `IllegalArgumentException` when `args` is empty. BTW, @LeTex, that is the condition that does it. In this case, `orElseThrow()` is better, since it clearly states the desired intent. – Andreas Apr 04 '16 at 20:34
2

The other answers have already explained to you why your code is (not) working: in the comparison args[i] < args[0], you always compare to the first value of your array.

One remark: if you are using Java 8, there is a somewhat more readable solution:

import java.util.stream.IntStream;
public class Test {
  public static void main(String[] args) {
    int[] array = {78,56,232,12,11,43};
    int min     = IntStream.of(array).min().getAsInt();
    System.out.println("Minimum: "+min);
  }
}
F. Knorr
  • 3,045
  • 15
  • 22
1

What you are doing is copying the contents of args[0] into smallest. arg[0] and smallest are not the same memory locations.

In the first code block you are updating the contents of smallest if the ith value is less than the 0th. Updating smallest will only update the value in that variable, not in args[0]

In the second code block you are both comparing, and updating, smallest with the values from args[i].


You need to understand what happens when you write something like int smallest. This allocates a new portion of memory for that variable. Running the code int smallest = 1 will put 1 in smallest.

If you have two different variables you will have two distinct memory locations, even if you write smallest = largest. All this does is copy the contents from largest into smallest.

This can be confusing when you have objects, rather than primitive types, being copied.
Obviously, in the case of primitives the value (for example 1) is copied from one variable to another. You'd end up with the case where smallest = 1 and largest = 1.
When it comes to objects it's a little different. In the case of Object smallest = new Object(), smallest would not contain an Object but rather the location that Object exists in memory. If you now do largest = smallest you would be copying the location, not the actual object.

If you're interested in this you can read more about it from one of my favourite answers on here: Is Java “pass-by-reference” or “pass-by-value”?

Community
  • 1
  • 1
Tiz
  • 680
  • 5
  • 17
0

It is because by doing smallest = args[i]; you are updating the smallest value in smallest variable and not args[0].

In your first solution you are comparing each and every value in the array with args[0] but if the value of any ith element is found smaller then you update the smallest variable instead of args[0].

You should update args[0] if you want your first code snippet to work.

Here is the corrected code snippet:

public class SmallestIntegerFinder {
    public int findSmallestInt(int[] args) {
        int smallest = args[0];
        for(int i=1; i < args.length; ++i) {
            if(args[i] < args[0]){
                args[0] = args[i];
            }
        }
        return args[0];
    }
}
user2004685
  • 9,548
  • 5
  • 37
  • 54
  • 1
    That updates the input, which is very likely not a good idea. But, if you really want to do this, remove variable `smallest` and return `args[0]`. – Andreas Apr 04 '16 at 20:13
  • @Andreas I know. But the question is more about *"Why the first code is not working but second code is!"* – user2004685 Apr 04 '16 at 20:15
  • 1
    Well, your code is not working either, because you're returning `smallest`, which has the value `arg[0]` *initially* had, so you're not returning the smallest value, but the first value. In my opinion, you tried to fix the code by changing the wrong thing. Changing `args[0]` to `smallest` in the `if` statement would have worked too, and without modifying the input array. – Andreas Apr 04 '16 at 20:28
  • @Andreas Either you haven't read the question properly or you misunderstood it completely. That's the whole point. OP wants to know why his first code is not working. He is doing the exactly same thing which you suggested in the second code. Thanks for highlighting the typo in the code though. I have fixed it. :) – user2004685 Apr 05 '16 at 07:40
  • 1
    No, the whole point of the question is what the difference is between using `args[0]` or `smallest` in the `if` statement. That is, in the *expression*, not the block. You are suggesting a totally different solution, which is to change the *block* to use `args[0]`, rather than changing the *expression* to use `smallest`, thereby introducing the potentially unwanted side-effect of mutating the input parameter. – Andreas Apr 05 '16 at 18:32
0

The problem is that you are comparing with args[0]. You should compare with the the smaller, so that if there is something smaller than the smaller it will be the new smaller :)

this should work:

public static int findSmallestInt(int[] args) {
    int smallest = args[0];
    for (int i = 1; i < args.length; ++i) {
        if (args[i] < smallest ) {
            smallest = args[i];
        }
    }
    return smallest;
}
LeTex
  • 1,452
  • 1
  • 14
  • 28
0

The other answers have told you why the first bit of code doesn't work and offered a lot of alternatives, but allow me to break down exactly where your code breaks. I feel this will be helpful in avoiding similar mistakes.

Here is your original code:

public class SmallestIntegerFinder {
    public int findSmallestInt(int[] args){
        int smallest = args[0];
        for(int i=1; i < args.length; ++i){
            if(args[i] < args[0]){
                smallest = args[i];
            }
        }
        return smallest;
     }
 }

And here is your input: {78,56,232,12,11,43}

Your original code works perfectly fine up to a certain point, but it's ultimately the comparison args[i] < args[0] that causes your code to break.

As your code loops through the array, at some point smallest contains the correct value, 11. But since 11 is not the last element in your array, the code does one more comparison for 43. Since your comparison is always with args[0] = 56, your code checks if 43 is less than 56, and since it is, overwrites smallest with 43, causing you to get the wrong value.

Changing the comparison to args[i] < smallest avoids this problem, because the last iteration of your loop will now check if 43 is less than 11. Since it is not, your function returns the correct value, 11.

NAMS
  • 983
  • 7
  • 17
0

There's a simpler solution to this:

final List<Integer> myList = Arrays.asList(78,56,232,12,11,43);
int smallest = myList.stream()
      .sorted()
      .findFirst()
      .get();
System.out.println("Smallest number is "+smallest);
Sina Madani
  • 1,246
  • 3
  • 15
  • 27
  • Define *simpler*. Sorting is more expensive than a linear traversal through the array. – Srini Apr 04 '16 at 21:59
  • Simpler means more readable and fewer lines of code than using boilerplate for loops. Unless you're running the program over a huge list on a computer from the 1980s there's no significant performance difference. – Sina Madani Apr 05 '16 at 15:13
  • You could still use `IntStream.of(array).min().getAsInt()` like other answers have pointed out, instead of sorting the array, which is a `log(size(array))` factor more expensive. – Srini Apr 05 '16 at 16:25
  • I agree, that is better. Anything is better than using C-style code ;) – Sina Madani Apr 06 '16 at 11:50