3

Java noob here. I want to sort an array of strings that contain periods / dots from smallest to largest.

So an array containing:

1.0.3
1.0.12
1.0.2

Is incorrectly being sorted like this:

1.0.12
1.0.2
1.0.3

When sorted correctly should be:

1.0.2
1.0.3
1.0.12

Here is the code I have so far, but it sorts it incorrectly.

public static String[] sort(String[] l) {
        String[] ll=new String[l.length];
        for(int i=0;i<l.length;i++)
        {

        }

        for (int i = 0; i < l.length - 1; ++i) {
            int minIndex = i;
            for (int j = i + 1; j < l.length; ++j) {

                if (l[j].compareTo(l[minIndex]) < 0) {
                    minIndex = j;
                }
            }

            String temp = l[i];
            l[i] = l[minIndex];
            l[minIndex] = temp;


        }
        return l;


    }
6
  • You can use the split method on the string to get an array of strings like String[] values = ll.split("\\.") - one needs to escape the dot. Commented Jun 18, 2017 at 16:46
  • 3
    "I read up that the comparator method should help this work, but I am not sure if I can implement in a method." Well Comparator is an interface, not a method - what makes you think implementing it wouldn't work? Commented Jun 18, 2017 at 16:54
  • I guess i had a misconception that Comparator is only for classes. I will look into it, thank you. Commented Jun 18, 2017 at 17:09
  • +1 to @JonSkeet's comment. The correct solution here is to implement a comparator. Then you can use the standard Arrays.sort method to sort it with your comparator, meaning you don't need to implement sorting yourself. Commented Jun 18, 2017 at 17:12
  • You're probably getting confused with Comparable, which you would need a class to implement. Comparator's are much simpler to work with for this kind of problem. Commented Jun 18, 2017 at 17:14

3 Answers 3

3

EDIT Complete, runnable version.

Using a class, it may be simpler:

public class Version implements Comparable<Version> {

   public final int     major;
   public final Integer minor;
   public final Integer patch;

   public Version( String ver ) {
      final String[] parts = ver.split("\\.");
      this.major = Integer.parseInt( parts[0] );
      if( parts.length > 1 ) {
         this.minor = Integer.parseInt( parts[1] );
         if( parts.length > 2 ) {
            this.patch = Integer.parseInt( parts[2] );
         }
         else {
            this.patch = null;
         }
      }
      else {
         this.minor = null;
         this.patch = null;
      }
   }

   @Override
   public int compareTo( Version right ) {
      int diff = this.major - right.major;
      if( diff != 0 ) {
         return diff;
      }
      if( this.minor == null && right.minor == null ) {
         return 0;
      }
      if( this.minor == null && right.minor != null ) {
         return -1;
      }
      if( this.minor != null && right.minor == null ) {
         return +1;
      }
      diff = this.minor - right.minor;
      if( diff != 0 ) {
         return diff;
      }
      if( this.patch == null && right.patch == null ) {
         return 0;
      }
      if( this.patch == null && right.patch != null ) {
         return -1;
      }
      if( this.patch != null && right.patch == null ) {
         return +1;
      }
      diff = this.patch - right.patch;
      return diff;
   }

   @Override
   public String toString() {
      return String.format( "%d.%d.%d", major, minor, patch );
   }

   public static void main( String[] args ) {
      final List<Version> versions = new ArrayList<>( 20 );
      versions.add( new Version( "5.3" ));
      versions.add( new Version( "5.3.0" ));
      versions.add( new Version( "2.5" ));
      versions.add( new Version( "2.5.100" ));
      final Random r = new Random( System.currentTimeMillis());
      for( int i = 0; i < 20; ++i ) {
         final int maj = r.nextInt(  10 );
         final int min = r.nextInt(  10 );
         final int pat = r.nextInt( 100 );
         final Version v =
            new Version( String.format( "%d.%d.%d", maj, min, pat ));
         versions.add( v );
      }
      Collections.sort( versions );
      versions.forEach( System.err::println );
   }
}

Execution trace:

0.5.55
0.9.54
1.1.60
1.7.19
1.8.15
2.2.85
2.5.null
2.5.100
2.7.68
2.8.42
3.1.57
3.2.50
4.4.18
5.3.null
5.3.0
6.3.0
7.1.26
7.2.30
7.4.47
7.5.63
7.6.13
8.6.12
8.9.80
9.8.4
Sign up to request clarification or add additional context in comments.

3 Comments

Thank you for your answer, but I am required to do it in a method :(
... That's a very odd requirement. Good practice dictates splitting a problem into smaller problems and using one method or even class for each of those problems. Requiring a solution contained in a single method is requiring bad style.
Well of course you call the sort from a method! Comparisons​ don't just happen by themselves! @Aubin showed what to use as a step toward writing that method. Rejecting this piece of the solution for such a thing so clearly a misunderstanding would be high foolishness. Consider instead how it would fit in to your complete solution.
0

You can use streams to accomplish the task at hand. Instead of just comparing the strings as they're, you can split the strings on the delimiter . then compare each digit against others; When we find that two digits are equal between two or more strings we then use .thenComparingInt to further the comparison.

String[] array = {"1.0.3" ,"1.0.12", "1.0.2"};
String[] result = Arrays.stream(array)
        .sorted(Comparator.comparingInt((String x) -> Integer.parseInt(x.split("\\.")[0]))
        .thenComparingInt((String x) -> Integer.parseInt(x.split("\\.")[1]))
        .thenComparingInt((String x) -> Integer.parseInt(x.split("\\.")[2]))).toArray(String[]::new);

the result array contains:

[1.0.2, 1.0.3, 1.0.12]

2 Comments

This answer assumes you will always have 3 parts in each string, but this is not specified as always being true in the description. Do not assume example data is always representative.
Assuming he has a definite maximum number of parts to work on, yes. But as fat as we see in the description, the number of sections could be arbitrarily high.
-1

Maybe this dirty to parse and convert to numbers but it is solve our problem.

public void test() {

    List<String> versions = new ArrayList<>(Arrays.asList(
            "1.0",
            "1.0.3",
            "1.1.131",
            "1.0.12",
            "1.0.2"
    ));
    List<String> expectedVersions = Arrays.asList(
            "1.0",
            "1.0.2",
            "1.0.3",
            "1.0.12",
            "1.1.131"
    );
    Comparator<String> versionComparator = new Comparator<String>() {

        @Override
        public int compare(String o1, String o2) {
            return parsedVersion(o1) - parsedVersion(o2);
        }

        private int parsedVersion(String version) {
            String cleared = version.replaceAll("\\.", "");
            return Integer.parseInt(cleared);
        }
    };
    versions.sort(versionComparator);
    System.out.println(versions.equals(expectedVersions));
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.