سؤال

So, i have this List of Folders which represent the Versions of a Program and i want to get the latest (there are some junk files next to the Folders!):

0.0.0.256
0.0.1.1
0.0.1.2
0.0.1.5
0.0.1.11
0.0.1.68
0.0.2.1

and so on.

If i want to get only the latest Version Folder here, how could i accomplish that?

Currently, i know that the version wont rise higher than 0.0.1.x for now, (the above is only an example) so i could use

    for(String name:names)
    {

        if (name.indexOf("0.0.1")==0)
        {


            ret = name;
        }
    }
    System.out.println("Current Installed Version Folder: "+ret);

but that wont last forever. How could i write some code, that will always give me the highest representive Version number? I can think of a way how to do it right now (checking the 0th char, then the 2nd, 4th and so on) but i think there is a smarter way. Any quick ideas?

هل كانت مفيدة؟

المحلول

The idea would be to use a comparator to compare each String (I removed the part which was using the Set) :

public static void main(String [] args){
    String [] names = { "0.0.1.1",
                        "1.0.1.1",
                        "0.0.1.2",
                        "0.0.1.5",
                        "0.0.1.11",
                        "0.0.0.100",
                        "0.0.0.256",
                        "0.0.2.1",
                        "0.0.1.68"};
    String maxVersion = names[0];

    for(int i = 1; i < names.length; i++){
        if(compare(maxVersion, names[i]) == 1)
            maxVersion = names[i];
    }
    System.out.print(maxVersion);
}
static int compare(String a, String b){
     String[] sA = a.split("\\.");
     String[] sB = b.split("\\.");
     for(int i = 0; i < sA.length; i++){
        int cmp = Integer.compare(Integer.parseInt(sB[i]), Integer.parseInt(sA[i]));
        if(cmp != 0)
            return cmp;
     }
    return 0;
}

Which outputs:

"1.0.1.1"

Note that this assume that each version number has the same length, but you can change this by checking both the length of the resulting arrays when splitting.


i got another problem: i got some files next to the Version Folders, so i can't get the names List from File.list()

You can provide a FileNameFilter with the listFiles method:

File file = new File("/pathToVersionFolders");
File[] files = file.listFiles(new FilenameFilter() {
  @Override
  public boolean accept(File dir, String name) {
      return new File(dir, name).isDirectory();
  }
});

Now you have only the directories. If you want to get only the names, you can use list.

نصائح أخرى

If you want to use the Java 8 Stream API you have to write a custom comparator.

List<String> sortedVersions = versions.stream().sorted((o1, o2) -> {
     String[] o1Split = o1.split("\\.");
     String[] o2Split = o2.split("\\.");
     int i = 0;
     while (i++ < Math.min(o2Split.length, o1Split.length)) {
         int o1IntValue = Integer.parseInt(o1Split[i - 1]);
         int o2IntValue = Integer.parseInt(o2Split[i - 1]);
        if (o1IntValue != o2IntValue) {
            return o1IntValue - o2IntValue;
        }
    }
    return 0;
}).collect(Collectors.toList());

String highestVersion = sortedVersions.get(sortedVersions.size() - 1);
System.out.println(highestVersion);

The currently accepted answer assumes you always have the exact same numbering schemes, which is probably true in your case. The "junk files" that you've mentioned are then filtered out using an isDirectory() filter, but what if you had some junk directories?

A more generic solution would not care about the exact versioning scheme, but split the input file names into a set of numeric / non-numeric segments, and then order the files by matching segment numbers (numerically if both are numeric, alphanumerically otherwise). I've blogged about this approach here. The idea was inspired by this answer here. The comparator could look like this:

public final class FilenameComparator implements Comparator<String> {
    private static final Pattern NUMBERS = 
        Pattern.compile("(?<=\\D)(?=\\d)|(?<=\\d)(?=\\D)");
    @Override public final int compare(String o1, String o2) {
        // Optional "NULLS LAST" semantics:
        if (o1 == null || o2 == null)
            return o1 == null ? o2 == null ? 0 : -1 : 1;

        // Splitting both input strings by the above patterns
        String[] split1 = NUMBERS.split(o1);
        String[] split2 = NUMBERS.split(o2);
        for (int i = 0; i < Math.min(split1.length, split2.length); i++) {
            char c1 = split1[i].charAt(0);
            char c2 = split2[i].charAt(0);
            int cmp = 0;

            // If both segments start with a digit, sort them numerically using 
            // BigInteger to stay safe
            if (c1 >= '0' && c1 <= '9' && c2 >= 0 && c2 <= '9')
                cmp = new BigInteger(split1[i]).compareTo(new BigInteger(split2[i]));

            // If we haven't sorted numerically before, or if numeric sorting yielded 
            // equality (e.g 007 and 7) then sort lexicographically
            if (cmp == 0)
                cmp = split1[i].compareTo(split2[i]);

            // Abort once some prefix has unequal ordering
            if (cmp != 0)
                return cmp;
        }

        // If we reach this, then both strings have equally ordered prefixes, but 
        // maybe one string is longer than the other (i.e. has more segments)
        return split1.length - split2.length;
    }
}

Since version numbers will always have this structure [0-9]+(\.[0-9]+)* then you can scan the directory for folder names that fit this pattern.

Once you've got the list of version directories, then you can split them into the separate numbers (split on the '.' character) and then sort them on the columns going from left to right.

The are a lot of solutions. For example

  1. split your string by .
  2. Iterate over the resulting array and create integer by adding current number to the result * 10,
  3. Compare resulting numbers

Here is a kind of pseudo code.

long version = 0;
String[] parts = versionSpec.split("\\.");
for (String part : parts) {
    int n = part.length;
    version = version * n + Integer.parseInt(part);
}

// at this point you have numeric representation of the version.

Now you can compare versions as you want. For example you can implement your own Comparator.

EDIT: the solution is fixed. Now n is calculated dynamically.

This worked for me, but may not work for others depending on how the versions of a program are updated.

I used the lastModified property of Files to determine which version directory was the most recent to be modified. In my case, the most recently modified folder was also the most recent / highest version for the program. It saved me a lot of string parsing.

Use directory.listFiles() to get an array of all folders in that directory, then pass it to this method to get the index in the array of the last modified folder. fileList[index] would then be the program's latest version folder.

/**
 *  Determine the index in an array of files[] of the most recently modified file
 * by comparing the lastModified property from all files in the array.
 *
 * @param  fileList Array of files from a desired directory
 * @return Integer index of most recently modified file/directory.
 * Returns -1 if the File[] array is null. 
 */
public static int getLatestModified(File[] fileList){
    if(fileList!= null){
        long latestVersion = 0;
        int index = 0;
        for(int i = 0; i < fileList.length; i++){
            File currentDir = fileList[i];
            if(currentDir.lastModified() > latestVersion){
                latestVersion = currentDir.lastModified();
                index = i;
            }
        }
        return index;
    }else{
        System.out.println("Error: fileList is null.");
        return -1;
    }
}

Edit: If you have files and folders in the same directory for the versions, you could add an if statement with isDirectory to only get the lastModified property from folders.

With Java 8 you can use a stream and the natural order comparator. for example:

List<String> versions = Arrays.asList(
            "0.0.1.1",
            "1.0.1.1",
            "0.2.1.11",
            "0.0.1.2",
            "0.0.1.5",
            "0.1.11",
            "0.1.1.11",
            "0.0.0.100",
            "0.0.0.256",
            "2.0.0.256",
            "1.0.0.256",
            "0.0.2.1",
            "0.0.1.68");

    String highest = versions.stream()
            .sorted(Comparator.naturalOrder())
            .collect(Collectors.toList())
            .get(versions.size() - 1);

    System.out.println(highest);
مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top