3

I have a text file containing the following strings (which are versions of a software):

1_10_2_0_154
3_10_5_2_10
2_10_4_1
3_10_5_1_37

I'm trying to find the most recent version, in this case 3_10_5_2_10 is the version that I'm trying to display using java.

For the moment, here is my code:

    BufferedReader br;
    String version;
    ArrayList<List<Integer>> array = new ArrayList<List<Integer>>();
    List<Integer> liste = new ArrayList<Integer>();

    try{
        br = new BufferedReader(new FileReader(new File(FILEPATH)));

        while((version= br.readLine()) != null)
        {
            liste = Arrays.asList(version.split("_")).stream().

    map(s -> Integer.parseInt(s.trim())).collect(Collectors.toList());

            array.add(liste);
        }

        for(int i = 0; i < array.size(); i++)
        {   
            for (List l: array)
            {
                Object z = l.get(i);
                List<Object> listes = new ArrayList<Object>();
                listes.add(z);
                System.out.println(listes);
            }               
        }
        br.close();

        System.out.println(array);
    }catch(FileNotFoundException e){
        e.printStackTrace();
    }catch(IOException e){
        e.printStackTrace();
    }      

I made a loop to save strings to ArrayList> like:

[[1,10,2,0,154] , [3,10,5,2,10], [2,10,4,1], [3,10,5,1,37]]

I want to get the elements of each list and compare them to find the most biggest one (most recent one) but I don't know to do that..

Siya
  • 101
  • 1
  • 1
  • 10

7 Answers7

4

I sugguest you a object approach, define a class named Version with compareTo method, then using method sort on Collections class you can simply sort your versions.

Advantages

  • Clean and Clear code
  • Data validation

Main:

public class Main {

    public static void main(String[] args){

        List<Version> versions = Arrays.asList(
                Version.create("1_10_2_0_154"),
                Version.create("3_10_5_2_10"),
                Version.create("2_10_4_1_49"),
                Version.create("3_10_5_1_37"));

        versions.sort(Version::compareTo);

        System.out.println(versions.get(0).toString());
    }

}

Version:

public class Version implements Comparable<Version> {

    private final int major;
    private final int minor;
    private final int bug;
    private final int release;
    private final int build;

    public Version(int major, int minor, int bug, int release, int build) {
        this.major = major;
        this.minor = minor;
        this.bug = bug;
        this.release = release;
        this.build = build;
    }

    public int getMajor() {
        return major;
    }

    public int getMinor() {
        return minor;
    }

    public int getBug() {
        return bug;
    }

    public int getRelease() {
        return release;
    }

    public int getBuild() {
        return build;
    }

    @Override
    public String toString() {
        return "Version{" +
                "major=" + major +
                ", minor=" + minor +
                ", bug=" + bug +
                ", release=" + release +
                ", build=" + build +
                '}';
    }



    public static Version create(String value){

        String[] splitRes = value.split("_");
        List<Integer> intValues = new ArrayList<>();

        for(String v : splitRes){
            intValues.add(Integer.parseInt(v));
        }

        return create(intValues);
    }

    public static Version create(List<Integer> values){

        if(Objects.requireNonNull(values).size() < 5)
            throw new IllegalArgumentException();

        return new Version(
                values.get(0),
                values.get(1),
                values.get(2),
                values.get(3),
                values.get(4)
        );
    }


    @Override
    public int compareTo(Version that) {
        if (this.major > that.major) {
            return -1;
        } else if (this.major < that.major) {
            return 1;
        }

        if (this.minor > that.minor) {
            return -1;
        } else if (this.minor < that.minor) {
            return 1;
        }

        if (this.bug > that.bug) {
            return -1;
        } else if (this.bug < that.bug) {
            return 1;
        }

        if (this.release > that.release) {
            return -1;
        } else if (this.release < that.release) {
            return 1;
        }

        if (this.build > that.build) {
            return -1;
        } else if (this.build < that.build) {
            return 1;
        }
        return 0;
    }
}

UPDATE 1

As suggested by @Henrik i updated the list sorting with a Java 8 approach.

UPDATE 2

I reversed the compareTo method so now you can simply do plain sort calling sort method on list and passing method reference Version::compareTo

UPDATE 3

A more dynamic solution for Version class:

public class Version implements Comparable<Version> {

    private final List<Integer> values;

    public Version(List<Integer> values) {
        this.values = values;
    }

    public List<Integer> getValues() {
        return values;
    }

    @Override
    public String toString() {

        return String.join("_", values
                .stream()
                .map(Object::toString)
                .collect(Collectors.toList()));
    }

    @Override
    public int compareTo(Version that) {

        List<Integer> thatValues = that.getValues();

        for(int index = 0; index < values.size(); index++){

            Integer value = values.get(index);
            Integer thatValue = thatValues.get(index);

            if (value > thatValue) {
                return -1;
            } else if (value < thatValue) {
                return 1;
            }
        }

        return 0;
    }


    public static Version create(String value){

        String[] splitRes = value.split("_");
        List<Integer> intValues = new ArrayList<>();

        for(String v : splitRes){
            intValues.add(Integer.parseInt(v));
        }

        return new Version(intValues);
    }
}
David Geirola
  • 616
  • 3
  • 17
  • 4
    I agree with this approach. Consider implementing the comparison using the utility methods added to the `Comparator` interface in Java 8, `comparingInt` and `thenComparingInt`. – Henrik Aasted Sørensen Mar 21 '18 at 14:07
  • 2
    i updated my answer with your sugguest, now i'm using **Comparator.reverseOrder()** to sort the list – David Geirola Mar 21 '18 at 14:17
  • 1
    Is it possible to make this code work if I have versions such as "3_10_0_4_53_15" instead of "3_10_0_4_53" ? – Siya Mar 21 '18 at 14:23
  • 1
    Will this list grow in the future ? You can add a new field and all will work but if the list is dynamic it takes a different solution(more flessible) – David Geirola Mar 21 '18 at 14:28
  • 1
    Yes the lenght of the versions can change like "3_10_0_4_53_15", "3_10_0_4_53" and even "3_10_0_4", your code seems to work perfectly with a fixed lenght of string, is it possible to make it more flexible as you said ? – Siya Mar 21 '18 at 15:39
  • Thank you so much @DavidGeirola you just saved my life ! – Siya Mar 25 '18 at 22:16
1

You can write a Comparator to compare two Lists

Comparator<List<Integer>> comparator = (list1, list2) -> {
    Iterator<Integer> iteratorA = list1.iterator();
    Iterator<Integer> iteratorB = list2.iterator();

    //It iterates through each list looking for an int that is not equal to determine which one precedes the other
    while (iteratorA.hasNext() && iteratorB.hasNext()) {
        int elementA = iteratorA.next();
        int elementB = iteratorB.next();

        if (elementA > elementB) {
            return 1;
        } else if (elementA < elementB) {
            return -1;
        }
    }
    //All elements seen so far are equal. Use the list size to decide
    return iteratorA.hasNext() ? 1 : iteratorB.hasNext() ? -1 : 0;
};

You can sort it as

Collections.sort(list, comparator);

EDIT: You can refer to David Geirola's answer to convert the version string as a POJO and move the comparator logic inside that. But that is highly tied/coupled to the input string format. My solution works for any List<List<Integer>>.

Thiyagu
  • 17,362
  • 5
  • 42
  • 79
0

A simple object oriented approach would be to create object, representing version number, let's call it VersionNumber, which would have a constructor of a factory method that does the parsing of the string. This VersionNumber class should implement interface Comparable and implement method compareTo.

Here is a hint for using Comparable Why should a Java class implement comparable?

Then you can easily write an algorithm to find the max version or google some library that would do it for you.

Michal Krasny
  • 5,434
  • 7
  • 36
  • 64
0

It is not optimized but should work. You can use both of comparators.

static List<String> versions = Arrays.asList(
        "1_10_2_0_154",
        "3_10_5_2_10",
        "2_10_4_1_49",
        "3_10_5_1_37");

static Comparator<List<Integer>> c = (o1,o2) -> {
    int length = o1.size()>o2.size()?o2.size():o1.size();
    for (int i = 0; i < length; i++) {
        int i1 = o1.get(i);
        int i2 = o2.get(i);
        if (i1 != i2)
            return i1 - i2;
    }
    return 0;
};
static Comparator<List<Integer>> c2 = (o1,o2) -> {
    Iterator<Integer> i1=o1.iterator();
    Iterator<Integer> i2=o2.iterator();
    while (i1.hasNext() && i2.hasNext()){
        int i = i1.next()-i2.next();
        if (i!=0) return i;
    }
    return 0;
};

static Optional<List<Integer>> getTheMostRecentVersion(List<String> versions) {
    return versions.stream().
            map(s -> Arrays.stream(s.split("_")).
                    map(Integer::parseInt).
                    collect(Collectors.toList())).max(c2);
}
V. Kar
  • 13
  • 2
0

I think that this text file could be very big and it is better to compare each line on the fly (instead of store all line into collection to sort it after):

public static String getMostRecentVersion(BufferedReader in) throws IOException {
    final Comparator<String[]> version = (s1, s2) -> {
        int res = 0;

        for (int i = 0; i < 5 && res == 0; i++)
            res = Integer.compare(Integer.parseInt(s1[i]), Integer.parseInt(s2[i]));

        return res;
    };

    String str;
    String resStr = null;
    String[] resPparts = null;

    while ((str = in.readLine()) != null) {
        String[] parts = str.split("_");

        if (resStr == null || version.compare(parts, resPparts) > 0) {
            resStr = str;
            resPparts = parts;
        }
    }

    return resStr;
}
Oleg Cherednik
  • 17,377
  • 4
  • 21
  • 35
0

A general ListComparator should help.

static class ListComparator<T extends Comparable<T>> implements Comparator<List<T>> {

    @Override
    public int compare(List<T> o1, List<T> o2) {
        for (int i = 0; i < Math.max(o1.size(), o2.size()); i++) {
            int diff =
                    // Off the end of both - same.
                    i >= o1.size() && i >= o2.size() ? 0
                    // Off the end of 1 - the other is greater.
                    : i >= o1.size() ? -1
                    : i >= o2.size() ? 1
                    // Normal diff.
                    : o1.get(i).compareTo(o2.get(i));
            if (diff != 0) {
                return diff;
            }
        }
        return 0;
    }
}

private static final Comparator<List<Integer>> BY_VERSION = new ListComparator<Integer>().reversed();

public void test(String[] args) {
    String[] tests = {
            "1_10_2_0_154",
            "3_10_5_2_10",
            "2_10_4_1_49",
            "3_10_5_1_37",
            "3_10_5_1_37_0"
    };
    System.out.println("Before: " + Arrays.toString(tests));
    System.out.println("After:  " + Arrays.stream(tests)
            // Split into parts.
            .map(s -> s.split("_"))
            // Map String[] to List<Integer>
            .map(a -> Arrays.stream(a).map(s -> Integer.valueOf(s)).collect(Collectors.toList()))
            // Sort it.
            .sorted(BY_VERSION)
            // Back to a new list.
            .collect(Collectors.toList()));
}
OldCurmudgeon
  • 64,482
  • 16
  • 119
  • 213
-2

slap your arrays together into a number then just do number comparison.

class Scratch
{
    public static void main(String[] args)
    {
        List<List<Integer>> arr = new ArrayList<>();
        arr.add(fromArray(new Integer[]{1,10,2,0,154}));
        arr.add(fromArray(new Integer[]{3,10,5,2,10}));
        arr.add(fromArray(new Integer[]{2,10,4,1,49}));
        arr.add(fromArray(new Integer[]{3,10,5,1,37}));

        Integer[] maxLengths = {0,0,0,0,0};
        for (List<Integer> v : arr)
        {
            for(int idx = 0; idx < v.size(); idx++)
            {
                Integer n = v.get(idx);
                int curMaxLen = maxLengths[idx];
                maxLengths[idx] = Math.max(n.toString().length(), curMaxLen);
            }
        }
        Long largest = arr.stream().map(v -> {
            StringBuilder result = new StringBuilder();
            for(int idx = 0; idx < v.size(); idx++)
            {
                Integer n = v.get(idx);
                int maxLen = maxLengths[idx];
                result.append(String.format("%-" + maxLen + 's', n).replace(' ', '0'));
            }
            return result.toString();
        }).map(Long::valueOf).max(Comparator.naturalOrder()).get();
        System.out.println(largest);
    }

    public static List<Integer> fromArray(Integer[] array)
    {
        List<Integer> list = new ArrayList<>();
        Collections.addAll(list, array);
        return list;
    }
}
aholt
  • 2,829
  • 2
  • 10
  • 13