4

I have fours variables that call different methods:

public String[] longestSide(){
     ArrayList<T> western = getWestern();
     ArrayList<T> eastern = getEastern();
     ArrayList<T> northern = getNorthern();
     ArrayList<T> southern = getSouthern();

   return //theLongestOne??
}

Instead of writing a bunch of if-else statements, what is the shortcut to find out which of the arraylists has the longest length and return it? Thanks!

6 Answers6

8
return Collections.max(Arrays.asList(western, eastern, northern, southern),
                       (a, b) -> Integer.compare(a.length, b.length));

If not on Java 8 yet, the same code can be written as

return Collections.max(Arrays.asList(western, eastern, northern, southern),
                       new Comparator<String[]> {
                           @Override
                           public int compare(String[] a, String[] b) {
                               return Integer.compare(a.length, b.length));
                           }
                        });

If what you have is in fact 4 List<String>, and not 4 arrays as in the original question, then it's even simpler:

return Collections.max(Arrays.asList(western, eastern, northern, southern),
                       Comparator.comparing(List::size));

which is equivalent to

return Collections.max(Arrays.asList(western, eastern, northern, southern),
                       new Comparator<List<String>> {
                           @Override
                           public int compare(List<String> a, List<String> b) {
                               return Integer.compare(a.size(), b.size());
                           }
                        });
JB Nizet
  • 678,734
  • 91
  • 1,224
  • 1,255
  • Read the javadoc. Collections.max() takes a Collection as argument. ArrayList is a Collection. So yes, it works with an ArrayList. – JB Nizet Sep 20 '15 at 07:27
  • @John, you will have to create a List that contains the ArrayLists and feed it to Collections.max() – Sharon Ben Asher Sep 20 '15 at 07:30
  • @JBNizet, I actually have Arraylists instead of arrays (I thought the syntax would be the same for both), i tried your way but its giving me error on this: `(a, b) -> Integer.compare(a.length, b.length));`. Could you please reply me one more time? –  Sep 20 '15 at 07:31
  • the other advantage of this solution over mine (below) is that it scales better when more arrays need to ba compared... – Sharon Ben Asher Sep 20 '15 at 07:32
  • 1
    @John , change to this `(a, b) -> Integer.compare(a.size(), b.size()));` – Sharon Ben Asher Sep 20 '15 at 07:33
  • @John arrays have a length attribute. Collections have a size() method. Please don't use these lines if you don't understand them. Take the time to read the javadoc of the methods used to understand what they do. – JB Nizet Sep 20 '15 at 07:35
  • @JBNizet, sorry for botherin, Im getting an error on this `(List::size)`. Is there smth wrong with that? –  Sep 20 '15 at 07:36
  • @JBNizet, `Multiple markers at this line - List cannot be resolved to a variable - Syntax error on tokens, delete these tokens`, should there be two colons in between? –  Sep 20 '15 at 07:39
  • So, you didn't import the class java.util.List. Yes, there should be two colons. That is a method reference. But as clearly indicated in my answer, it's only valid (like the first lambda-based snippet) in Java 8. If you're using an older version, use the answers with comparators defined as inner classes. – JB Nizet Sep 20 '15 at 07:40
3
String maxLength = Math.max(Math.max(western.length, eastern.length), Math.max(southern.length, northern.length));
String[] longest = 
    western.length == maxLength ? western :
    eastern.length == maxLength ? eastern :
    southern.length == maxLength ? southern :
    northern;
Sharon Ben Asher
  • 13,849
  • 5
  • 33
  • 47
3

Define a method as follows:

public Sting[] longestOf(String[] a, String[] b){
 if(a.length>b.length) {
   return a;
 }
 return b;
}

Now, you can do the following in your longestSide() method:

return longestOf(longestOf(western, eastern), longestOf(northern, southern));
Mustafa
  • 161
  • 1
  • 5
0
return Collections.max(Arrays.asList(getWestern(), getEastern(), getNorthern(),  getSouthern()), new Comparator<String[]>() {
    @Override
    public int compare(String[] first, String[] second) {
         return first.length - second.length;
    }
});
yelliver
  • 5,648
  • 5
  • 34
  • 65
  • You forgot the return statement. And using subtraction is generally a bad idea, due to integer overflow if really large positive and negative values are compared. Won't happen here, but you should prefer Integer.compare(), which is both clearer and always correct. – JB Nizet Sep 20 '15 at 07:46
  • generally a bad idea, but this is compare array length, length is never negative – yelliver Sep 20 '15 at 08:07
  • Hence "Won't happen here" in my comment. The problem is that this will be seen as a nice trick by readers where the problem *could* happen, and they will thus introduce a bug in their code by copying that trick everywhere. Integer.compare() doesn't have that problem: it is always correct. Been there, done that. – JB Nizet Sep 20 '15 at 08:10
0

You can do it in another way.There can be some compilation problem, but the general idea is clear:

private List<T> longest;

// Decorator method, which will return array list, but will also calculate required longest direction.
public <T> List<T> calculateAndGet(List<T> list) {

     if (Objects.isNull(longest) || longest.size() < list.size()) {
           longest = list.size();
     }

     return list;
}

public String[] longestSide(){
     List<T> western = calculateAndGet(getWestern());
     List<T> eastern = calculateAndGet(getEastern());
     List<T> northern = calculateAndGet(getNorthern());
     List<T> southern = calculateAndGet(getSouthern());

   return longest.toArray(new String[longest.size()]);
}

I also changed ArrayList to List. Is there any specific logic not to use "Coding to interfaces" principle?

Ivan Ursul
  • 3,251
  • 3
  • 18
  • 30
-1

Implementing as suggested by Shai in a comment:

public String[] longestSide(){
    String[] western = getWestern();
    String[] eastern = getEastern();
    String[] northern = getNorthern();
    String[] southern = getSouthern();

    String[] longest = null;
    for (String[] a : new String[][] {western,eastern,northern,southern})
        if (longest == null || a.length > longest.length)
            longest = a;
    return longest;
}

Or using a helper method for a List (or other Collection) as indicated by updated question:

@SafeVarargs
public static <L extends Collection<?>> L longestOf(L ... lists) {
    L longest = lists[0];
    for (int i = 1; i < lists.length; i++)
        if (lists[i].size() > longest.size())
            longest = lists[i];
    return longest;
}

Use like this:

return longestOf(western, eastern, northern, southern);
Andreas
  • 154,647
  • 11
  • 152
  • 247
  • 1
    There are fastest ways to do this.Please remove your answer, because there will be lots of minuses for it. – Ivan Ursul Sep 20 '15 at 07:28
  • @IvanUrsul OP didn't ask for fastest way, besides this is on par with fastest, unless you can show me faster? – Andreas Sep 20 '15 at 07:33
  • If you asking for fastest way, then just do a decorator method(all four methods return String[]), which will store somewhere longest direction, for example, in the field, and each time check whether current longest direction is longer, if yes, then equate it. – Ivan Ursul Sep 20 '15 at 07:42
  • @IvanUrsul Isn't that exactly what I'm doing? Store longest in variable, check the others and update variable if longer found. – Andreas Sep 20 '15 at 07:52
  • No, that's not. Have you heard about decorator pattern ?Just do like String[] western = decoratorMethod(getWestern);... – Ivan Ursul Sep 20 '15 at 09:08
  • @IvanUrsul I have, but since it's unlikely the code in question is going to be called in a tight loop, the performance difference, if any, between 5 method calls to the decorator vs. a `for` loop of an array is insignificant, and I don't see why that would gain down-votes. Besides I don't even see your decorator pattern suggested anywhere, so instead of hating on a valid answer, why not provide yours? – Andreas Sep 20 '15 at 09:29
  • You are doing unnecessary things - creating double array, looping throughout it, doing some operations. – Ivan Ursul Sep 20 '15 at 09:34
  • @IvanUrsul So why didn't you make the same argument for the two `Collections.max(Arrays.asList(...` answers, one of which has the highest votes, and tell them to delete their answers too? What did I do to you to be singled out? – Andreas Sep 20 '15 at 09:38
  • Because his answer is short, and your answer is not. – Ivan Ursul Sep 20 '15 at 09:43
  • @IvanUrsul So you're now changing your argument from performance to conciseness? Accepted answer is actually longer than mine. Sorry, your arguments and inconsistent application of them don't hold up, especially since you couldn't be bothered to provide your supposedly better solution. – Andreas Sep 20 '15 at 09:48
  • Did you read the question. Guy said that he don't want to write bunch of if-else statements.Why are you linking this question to performance?But even if you do that, your answer is nor best in performance, nor best in conciseness. – Ivan Ursul Sep 20 '15 at 09:51
  • I would better recommend you to remove your message, because there can be more negative scores. – Ivan Ursul Sep 20 '15 at 09:52
  • @IvanUrsul I have **1** if statement and no else clause. Yours would too. Argument failed. --- You said "fastest way", not me. --- I can spare a few points for down-votes, guess you can't. --- Anyway, this discussion is going nowhere. Godspeed. – Andreas Sep 20 '15 at 09:57