Getting Max value from x.y.z formatted Number - java

Is there an easy way of finding the MAX number from the list where number is stored in x.y.z format? e.g. To manage some system versions.
I have tried Collection.max(list) and that does not work.
Sample Code:
public static void main(String args[])
{
List<String> list = new ArrayList<String>();
list.add("1.0.0");
list.add("1.1.0");
list.add("1.9.0");
list.add("1.10.0");
System.out.println(Collections.max(list));
}
Expected: 1.10.0
Result: 1.9
Thanks for your time.

Try to use this one :
Collections.max(myList, new Comparator<String>() {
#Override
public int compare(String lhs, String rhs) {
String[] first = lhs.split("\\.");
String[] second = rhs.split("\\.");
for (int i = 0; i < first.length; i++) {
if(Integer.valueOf(first[i]) > Integer.valueOf(second[i])) {
return 1;
}
if(Integer.valueOf(first[i]) < Integer.valueOf(second[i])) {
return -1;
}
}
return 0;
}
});

Well for one thing, you need to ensure that Java knows they are numbers - at the moment they're just Strings, and strings sort lexigraphically (i.e. in "alphabetical order").
My approach to this would be to create a small class that implements Comparable, which will then work automatically with sorting and comparison logic. Something like this perhaps:
public class VersionNumber implements Comparable<VersionNumber> {
public final int major;
public final int minor;
public final int patch;
// Constructor etc. elided
public int compareTo(VersionNumber other) {
if (other.major != major) return major - other.major;
if (other.minor != minor) return minor - other.minor;
return patch - other.patch;
}
}
Parsing the string to create instances of this class is left as an exercise to the reader!

You may have to write a custom Comparator for comparing version number strings:
public class VersionComparator extends Comparator<String> {
#Override
public int compare(String o1, String o2) {
// Get major/minor/revison numbers by splitting strings at dots
String[] p1 = o1.split("\\.");
String[] p2 = o2.split("\\.");
// Compare major versions then minor then revision until a difference found
for(int i = 0; i < (p1.length < p2.length) ? p1.length : p2.length; i++) {
int result = Integer.valueOf(p1[i]).compareTo(Integer.valueOf(p2[i]));
if(result != 0) return result;
}
// Return zero if they're identical
return 0;
}
}
The you can use this comparator with the Collections.max function:
Collections.max(list, new VarsionComparator());

You can use version of max with the specified comparator:
System.out.println(Collections.max(list, new Comparator<String>() {
public int compare(String s1, String s2)
{
StringTokenizer st1 = new StringTokenizer(s1,".");
StringTokenizer st2 = new StringTokenizer(s2,".");
int res = 0;
String t1, t2;
while(st1.hasMoreTokens() && st2.hasMoreTokens())
{
t1 = st1.nextToken();
t2 = st2.nextToken();
res = Integer.valueOf(t1).compareTo(Integer.valueOf(t2));
}
if(res == 0)
{
res = st1.hasMoreTokens() ? 1 : (st2.hasMoreTokens() ? -1 : 0);
}
return res;
}
public boolean equals(Object obj) { return false; }
}));

This will give you 1.9 because it will not consider second number to be 10, it will treat it as 1 first and then 9
Edit
If you want to do it manually, then
Split your number on basis of "."
Check manually which number is greater.

Related

object sorting using comparable interface

i have one class which have 4 int fields . i want to sort objects array by some mathematical operation on fields .I tried below code but sorting is not happening.
class Cust1 implements Comparable<Cust1>{
int a;
int o;
int s;
int p;
#Override
public int compareTo(Cust1 b) {
if(this.a + this.s <= b.a + b.s)
{
return 1;
}
else {
return 0;
}
}
}
public class Test5 {
public static void main (String args[]) throws Exception
{
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int n = Integer.parseInt(br.readLine());
Cust1[] cust = new Cust1[n];
for(int i=0;i<n ;i++)
{
Cust1 a = new Cust1();
String[] str = br.readLine().split(" ");
a.a = Integer.parseInt(str[0]);
a.o = Integer.parseInt(str[1]);
a.s = Integer.parseInt(str[2]);
a.p = Integer.parseInt(str[3]);
cust[i] =a;
}
Arrays.sort(cust, new Comparator<Cust1>() {
#Override
public int compare(Cust1 o1, Cust1 o2) {
return o1.compareTo(o2);
}
});
}
}
Based on your code snippet: you don't need to provide Comparator, since Cust1 already implements Comparable. So, this should be enough:
Arrays.sort(cust);
Also, Cust1 implementation of Comparable doesn't really tell, when one object is less then other. Probably, you meant something like this:
#Override
public int compareTo(Cust1 b) {
if(this.a + this.s < b.a + b.s) {
return 1;
} else if (this.a + this.s > b.a + b.s) {
return -1;
} else {
return 0;
}
}
But it's hard to tell, what exact implementation of Comparable should be without more details (for instance, for some reason fields o and p are not involved in comparison at all).
You comparator work wrong. It should return:
>0 - current object is greater than another one
0 - current object is equal to another one
<0 - current object is less than another one
class Cust1 implements Comparable {
int a;
int o;
int s;
int p;
#Override
public int compareTo(Cust1 b) {
return Integer.compare(a + s, b.a + b.s);
}
}
And you do not have to provide additional comparator to Arrays.sort() since Cust1 already implements Comparable.

Need a code to make tree structure from version names

I have an array of versions such as ["1.0.0.0","1.5.0.0","1.5.0.1","1.5.0.2","1.5.0.3","1.5.0.4","1.5.0.7","1.6.0.0","1.6.0.1","1.13.0.0","1.13.1.0","1.13.1.1","1.13.1.2","1.13.1.3","1.13.1.4","1.22.0.0","1.22.1.0","1.22.1.1"]
I need to map it into tree like
1.0.0.0
|1.5.0.0
||1.5.0.1
||1.5.0.2
||1.5.0.3
||1.5.0.4
||1.5.0.7
|1.6.0.0
||1.6.0.1
|1.13.0.0
||1.13.1.0
||1.13.1.1
||1.13.1.2
|1.22.0.0
||1.22.1.0
||1.22.1.1
Can any one help with this using Java
What do you want to achieve? This looks like you either want to print every version or to check versions.
For first case, iterate trough array and print it like:
System.out.println("your item")
In second case, you can simply check if your array contains version you are checking.
I assume that you would like to insert the input version into a Binary Search Tree (BST)
It will allow you to find requested versions in O(log(n)) time
These are the main steps to achieve your goal:
1) Use a java BST implementation.
2) Implement String Comparator, in order to determine which version is bigger.
3) Add elements to the tree.
4) Print elements in your favorite format.
1) I've used this implementation: https://www.cs.cmu.edu/~adamchik/15-121/lectures/Trees/code/BST.java
2) I've implemented a comparator that maps version strings to integers.
It allows me to compare the encoded numeric values of the versions
public class VersionsComparator implements Comparator {
#Override
public int compare(String s1, String s2) {
String versionPattern = "(\\d+)[.](\\d+)[.](\\d+)[.](\\d+)";
final int numOfMatchers = 2;
Pattern pattern = Pattern.compile(versionPattern);
Matcher[] matchers = new Matcher[numOfMatchers];
matchers[0] = pattern.matcher(s1);
matchers[1] = pattern.matcher(s2);
for (Matcher matcher : matchers) {
if(!matcher.matches()) {
throw new RuntimeException("Invalid version format");
}
}
int version1 = parseVersion(s1, matchers[0]);
int version2 = parseVersion(s2, matchers[1]);
return version2 - version1;
}
private int parseVersion(String version, Matcher matcher) {
int length = matcher.groupCount();
int[] v = new int[length];
int parsedVersion = 0;
for (int i = 0; i < length; i++) {
v[i] = Integer.parseInt(matcher.group(length - i));
parsedVersion += Math.pow(10, i) * v[i];
}
return parsedVersion;
}
}
3) Adding all of the strings to the tree:
private static BST getBST(String[] strArr) {
BST<String> bst = new BST<String>();
Arrays.asList(strArr).stream().forEach(str -> bst.insert(str));
return bst;
}
4) Printing the tree elements:
I've added my own printing style, by adding 2 methods to the BST class:
public void inOrderTraversalWithHierarchy() {
inOrderWithHierarchyHelper(root, 0);
}
private void inOrderWithHierarchyHelper(Node r, int level) {
if (r != null) {
inOrderWithHierarchyHelper(r.left, level + 1);
for (int i = 0; i < level; System.out.print("|"), i++);
System.out.println(r);
inOrderWithHierarchyHelper(r.right, level + 1);
}
}
This is the code of the client class:
public class CodeToMakeTreeStructureFromVersionNames {
public class VersionsComparator implements Comparator<String>{
#Override
public int compare(String s1, String s2) {
String versionPattern = "(\\d+)[.](\\d+)[.](\\d+)[.](\\d+)";
final int numOfMatchers = 2;
Pattern pattern = Pattern.compile(versionPattern);
Matcher[] matchers = new Matcher[numOfMatchers];
matchers[0] = pattern.matcher(s1);
matchers[1] = pattern.matcher(s2);
for (Matcher matcher : matchers) {
if(!matcher.matches()) {
throw new RuntimeException("Invalid version format");
}
}
int version1 = parseVersion(s1, matchers[0]);
int version2 = parseVersion(s2, matchers[1]);
return version2 - version1;
}
private int parseVersion(String version, Matcher matcher) {
int length = matcher.groupCount();
int[] v = new int[length];
int parsedVersion = 0;
for (int i = 0; i < length; i++) {
v[i] = Integer.parseInt(matcher.group(length - i));
parsedVersion += Math.pow(10, i) * v[i];
}
return parsedVersion;
}
}
public static void main(String[] args) {
String[] versions = {"1.0.0.0","1.5.0.0","1.5.0.1","1.5.0.2","1.5.0.3","1.5.0.4","1.5.0.7","1.6.0.0","1.6.0.1","1.13.0.0","1.13.1.0","1.13.1.1","1.13.1.2","1.13.1.3","1.13.1.4","1.22.0.0","1.22.1.0","1.22.1.1"};
printBST(getBST(versions));
}
private static BST<String> getBST(String[] strArr) {
BST<String> bst = new BST<String>();
Arrays.asList(strArr).stream().forEach(str -> bst.insert(str));
return bst;
}
private static void printBST(BST bst) {
bst.inOrderTraversalWithHierarchy();
}
}

Merge and order Lists

For any two ascending sorted ArrayList<Integer> such as
List<Integer> l1 = new ArrayList<Integer>();
l1.add(1);
l1.add(2);
l1.add(5);
l1.add(10);
and
List<Integer> l2 = new ArrayList<Integer>();
l2.add(1);
l2.add(3);
l2.add(5);
l2.add(11);
how to merge them into an ArrayList<Integer> whose values are
1,1,2,3,5,5,10,11
Update
Realised that Integer oversimplifies the problem; in fact these are lists of class
public class Tuple {
public boolean isComment;
public int location;
public String text;
public Tuple(boolean isAComment, int aLocation, String aText) {
isComment = isAComment;
location = aLocation;
text = aText;
}
}
As suggested, a valid solution requires a sorting, where location is first criterion, whether it is a comment is the second criterion.
This answer does not contain code, you'll have to figure it out for yourself.
Add the Lists to one another using addAll.
Sort the Lists using Collections.sort
Are you implementing merge-sort?
The "bycicle"-way (O(n)):
public List<Integer> merge (List<Integer> l1, List<Integer> l2) {
List<Integer> result = new ArrayList<>();
int i1 = 0, i2 = 0;
while (i1 < l1.size() && i2 < l2.size())
if (l1.get(i1) < l2.get(i2))
result.add (l1.get(i1++));
else
result.add (l2.get(i2++));
while (i1 < l1.size())
result.add (l1.get(i1++));
while (i2 < l2.size())
result.add (l2.get(i2++));
return result;
}
In case of List<Tuples> that wouldn't change much, just make your Tuple Comparable:
public class Tuple implement Comparable <Tuple> {
public boolean isComment;
public int location;
public String text;
public Tuple(boolean isAComment, int aLocation, String aText) {
isComment = isAComment;
location = aLocation;
text = aText;
}
public int compareTo (Tuple that) {
if (location == that.location)
return Boolean.compare (isComment, that.isComment);
else
return Integer.compare (location, that.location);
}
}
Then, instead of using < operator, you should use l1.get(i1).compareTo(l2.get(i2)) < 0

Change sort order of strings includes with a special character (e.g. "_")

A PHP script outputs a list of e-mail addresses in descending order like following:
_abc_#testmail.com
_abc45_#testmail.com
_abc2_#testmail.com
ypaux2aux#yahoo.com
yaremchuk56#testmail.com
vasillevn#hotmail.com
ugur#hotmail.com
twes#gmail.com
tukaux#yahoo.com
ttsetaux1#yahoo.com
tra#testmail.com
In Java, I'm creating an ArrayList from these e-mails, then sorting in descending order. The result is different:
ypaux2aux#yahoo.com
yaremchuk56#testmail.com
vasillevn#hotmail.com
ugur#hotmail.com
twes#gmail.com
tukaux#yahoo.com
ttsetaux1#yahoo.com
tra#testmail.com
_abc45_#testmail.com
_abc2_#testmail.com
_abc_#testmail.com
The difference is caused by the underscore "_". I want to achieve the same sort order as the PHP script. How can I do this? I've no access to the PHP code.
The Java test code I used is:
import java.util.ArrayList;
import java.util.Collections;
public class sorty {
public static void main(String[] args) {
ArrayList<String> listStrings = new ArrayList<>();
listStrings.add("_abc_#testmail.com");
listStrings.add("_abc45_#testmail.com");
listStrings.add("_abc2_#testmail.com");
listStrings.add("ypaux2aux#yahoo.com");
listStrings.add("yaremchuk56#testmail.com");
listStrings.add("vasillevn#hotmail.com");
listStrings.add("ugur#hotmail.com");
listStrings.add("twes#gmail.com");
listStrings.add("tukaux#yahoo.com");
listStrings.add("ttsetaux1#yahoo.com");
listStrings.add("tra#testmail.com");
for (int i = 0; i < listStrings.size(); i++) {
System.out.println(listStrings.get(i));
}
Collections.sort(listStrings);
Collections.reverse(listStrings);
for (int i = 0; i < listStrings.size(); i++) {
System.out.println(listStrings.get(i));
}
;
}
}
I would use an appropriate Collator. Implementing your own comparator isn't the
most trivial thing. The nicest would be if you where happy with one of the defaults. e.g.
Collections.sort(listStrings, Collator.getInstance(Locale.US));
Or similar.
If none of the existing ones works for you then using a rule based collator would make
your intent clearer then implementing a comparator imo:
String rules = "< a < b < c < '_'" //etc
Collections.sort(listStrings, new RuleBasedCollator(rules));
Sort using a custom comparator that understands underscores are special:
Collections.sort(listStrings, new Comparator<String>() {
#Override
public int compare(String o1, String o2) {
if (o1.startsWith("_") && o2.startsWith("_")) {
return compare(o1.substring(1), o2.substring(1));
}
if (o1.startsWith("_")) {
return 1;
}
if (o2.startsWith("_")) {
return -1;
}
return o1.compareTo(o2);
}
});
This will also handle the situation where multiple underscores are present. E.g. __foo will be considered after _foo.
To cope with arbitrary numbers of special characters, define them in an array (in your preferred order) and use a more advanced comparator:
Collections.sort(listStrings, new Comparator<String>() {
// declare in order of desired sort
private final String[] specialChars = { "_", ">" };
#Override
public int compare(String o1, String o2) {
/*
* CASES
*
* 1. Both start with same special char
*
* 2. Both start with a special char
*
* 3. One starts with a special char
*
* 4. None starts with a special char
*/
int o1SpecialIndex = -1;
int o2SpecialIndex = -1;
for (int i = 0; i < specialChars.length; i++) {
if (o1.startsWith(specialChars[i])) {
o1SpecialIndex = i;
}
if (o2.startsWith(specialChars[i])) {
o2SpecialIndex = i;
}
}
// case 1:
if (o1SpecialIndex != -1 && o1SpecialIndex == o2SpecialIndex) {
return compare(o1.substring(1), o2.substring(1));
}
// case 2:
if (o1SpecialIndex != -1 && o2SpecialIndex != -1) {
return o2SpecialIndex - o1SpecialIndex;
}
// case 3:
if (o1SpecialIndex != -1) {
return 1;
}
if (o2SpecialIndex != -1) {
return -1;
}
// case 4:
return o1.compareTo(o2);
}
});

Need to sort strings by part of the string

Say I have an array of strings:
String[] array = {
"2183417234 somerandomtexthere",
"1234123656 somemorerandomtexthere",
"1093241066 andevenmore",
"1243981234 you get what i mean",
//etc
};
How would I sort this array using the long (it's a long) at the start of the string, so it'll end up looking like this:
String[] array = {
"1093241066 andevenmore",
"1234123656 somemorerandomtexthere",
"1243981234 you get what i mean",
"2183417234 somerandomtexthere",
//etc
};
I've tried everyting from making it an arraylist and using Collections#sort to creating my own comparator, to using a sorted map / tree map and I just can't figure it out.
Thanks.
Use this function:
static long comparedValue(String s) {
return Long.valueOf(s.substring(0, s.indexOf(' ')));
}
and then define a Comparator in terms of it:
public int compare(String left, String right) {
return comparedValue(left) - comparedValue(right);
}
Using Google Guava:
List<String> unsorted = Arrays.asList(array);
Function<String, Long> longFunction = new Function<String, Long>() {
#Override public Long apply(String input) {
return Long.valueOf(input.split(" ")[0]);
}
};
List<String> sorted = Ordering.natural().onResultOf(longFunction).immutableSortedCopy(unsorted);
Or if you don't wanna use a List (you should always prefer collections to arrays):
Arrays.sort(array, Ordering.natural().onResultOf(longFunction));
The input that you have shown works perfectly fine. But that's because all of them have the same number of digits.
public static void main(String[] args) {
String[] array = { "2183417234 somerandomtexthere",
"1234123656 somemorerandomtexthere", "1093241066 andevenmore",
"1243981234 you get what i mean", "999 little shorter"
// etc
};
List<String> list = Arrays.asList(array);
Collections.sort(list);
System.out.println(list);
}
Problems start to occur, when you use some shorter numbers - as 999 shown above...
output will be:
[1093241066 andevenmore, 1234123656 somemorerandomtexthere, 1243981234 you get what i mean, 2183417234 somerandomtexthere, 999 little shorter]
So, to make it working allways - you need your custom comparator, that will be able to split given Strings, and then take the number part out of them, and compare them. Using #Marko Topolik solution:
static long comparedValue(String s) {
return Long.valueOf(s.substring(0, s.indexOf(' ')));
}
public int compare(String left, String right) {
long result = comparedValue(left) - comparedValue(right);
boolean numberPartAreEqual = result == 0;
if (numberPartAreEqual) {
result = left.compareTo(right);
}
return (int) result;
}
A custom comparator should work fine:
public class LongPrefixComparator implements Comparator<String> {
#Override
public int compare(String s1, String s2) {
final long pref1 = getPrefixValue(s1);
final long pref2 = getPrefixValue(s2);
return s1 == s2 ? 0 : s1 < s2 ? -1 : 1;
}
private static long getPrefixValue(String stg) {
int len = stg.indexOf(' ');
if (len > 0) {
try {
return Long.parseLong(stg.substring(0, len));
catch (NumberFormatException ignored) {}
}
return 0L;
}
}

Categories