JAVA code to handle versions and the comparisons.

Hello Buddies.

Sharing a small but useful piece of code, that can help you in handling version strings and comparisons in day-to-day coding.

Many a time, we struggle while comparing and transcoding the versions, which might take some time and can be frustrating as well.

So for my reference, I am keeping this snippet handy, and so is for you.

Check out the full project here, OR you may refer to the code shared below.


Happy Coding!




 package versionCheckDemo;  
 /**  
  * @author namit  
  * @version 2.0  
  *   
  * re-checking-in for testing develop branch  
  *   
  * */  
 public class VersionTester {  
  public static void main(String[] args) {  
   System.out.println("Part 1 - Generalize the version numbers to a standard format - a.b.c");  
   String input = "1.1";  
   update(input);  
   input = "1.1.1";  
   update(input);  
   input = "1";  
   update(input);  
   System.out.println("Part 2 - Get the main digit representing the version number ");  
   input = "1.0.1";  
   findVersion(input);  
   input = "54.1";  
   findVersion(input);  
   input = "100";  
   findVersion(input);  
   input = "100.c.c";  
   findVersion(input);  
   input = "100.cc.&@!#$$";  
   findVersion(input);  
   System.out.println("Part 3 - Comparing the versions, under the format a.b.c ");  
   String versionX = "2.3";  
   String minVersion = "2.5.5";  
   checkVersion(versionX, minVersion);  
   versionX = "2.7.9";  
   minVersion = "2.5.5";  
   checkVersion(versionX, minVersion);  
  }  
  /**  
   * Method to update the version numbers to a uniform pattern  
   * */  
  private static void update(String input) {  
   System.out.println("incoming >> " + input);  
   int occurence = countMatches(input, '.');  
   if (occurence == 0)  
    input += ".0.0";  
   else if (occurence == 1)  
    input += ".0";  
   System.out.println("outgoing >> " + input);  
   System.out.println("---------------");  
  }  
  public static int countMatches(final CharSequence str, final char ch) {  
   if (null == str) {  
    return 0;  
   }  
   int count = 0;  
   char[] arr = ((String) str).toCharArray();  
   for (char c : arr) {  
    if (c == ch)  
     count++;  
   }  
   // likewise you can go for  
   // org.apache.commons.lang3.StringUtils.StringUtils.countMatches(str, ch)  
   // for saving time of writing the count logic  
   return count;  
  }  
  /**  
   * Method to find the main version number  
   * */  
  private static void findVersion(String input) {  
   System.out.println("Incoming >> " + input);  
   String inputWithoutDots = input.replace(".", "");  
   if (inputWithoutDots.matches("[0-9]+")) {  
    int version = 0;  
    String[] arr = input.split("\\.");  
    version = Integer.valueOf(arr[0]);  
    System.out.println("Success! outgoing >> " + version);  
   } else {  
    System.out.println("error!");  
   }  
   System.out.println("---------------");  
  }  
  /**  
   * Method to compare the given version with a minimum accepted version  
   * */  
  private static void checkVersion(String versionX, String minVersion) {  
   String minVersionFormatted = String.format("%-4s", minVersion.replace(".", "")).replace(' ', '0');  
   int minVersionNum = Integer.valueOf(minVersionFormatted);  
   String formattedVersion = String.format("%-4s", versionX.replace(".", "")).replace(' ', '0');  
   int versionXNum = Integer.parseInt(formattedVersion);  
   System.out.println("Min Version - "+minVersion);  
   System.out.println("You provided - "+versionX);  
   if (versionXNum >= minVersionNum) {  
    System.out.println("Version Accepted!");  
   } else {  
    System.out.println("Version Rejected!");  
   }  
   System.out.println("---------------");  
  }  
 }  


OUTPUT:

 Part 1 - Generalize the version numbers to a standard format - a.b.c  
 incoming >> 1.1  
 outgoing >> 1.1.0  
 ---------------  
 incoming >> 1.1.1  
 outgoing >> 1.1.1  
 ---------------  
 incoming >> 1  
 outgoing >> 1.0.0  
 ---------------  
 Part 2 - Get the main digit representing the version number   
 Incoming >> 1.0.1  
 Success! outgoing >> 1  
 ---------------  
 Incoming >> 54.1  
 Success! outgoing >> 54  
 ---------------  
 Incoming >> 100  
 Success! outgoing >> 100  
 ---------------  
 Incoming >> 100.c.c  
 error!  
 ---------------  
 Incoming >> 100.cc.&@!#$$  
 error!  
 ---------------  
 Part 3 - Comparing the versions, under the format a.b.c   
 Min Version - 2.5.5  
 You provided - 2.3  
 Version Rejected!  
 ---------------  
 Min Version - 2.5.5  
 You provided - 2.7.9  
 Version Accepted!  
 ---------------  


Enum types in Java - A Superhero version



Hello Buddies.


This one is for Enum type.




  As Java Doc states -



" An enum type is a special data type that enables for a variable to be a set of predefined constants. The variable must be equal to one of the values that have been predefined for it. Common examples include compass directions (values of NORTH, SOUTH, EAST, and WEST) and the days of the week.You should use enum types any time you need to represent a fixed set of constants. "



Ok, that sounds cool, but can we have a working Demo that can depict where can we use it further?


Surely we can, and here is one example.


We have a scenario here - 


A superhero scenario. 


Superman, who is not willing to reveal his real name, Batman, hmmm we all know when he wants and he doesn't want to reveal his real name, and Deadpool who is not invited in the party, yet trying to sneak in.

So can we cater to the requirements here -
1. Provide Superman the data hiding.
2. Provide Batman his real name revealed, when he wants.
3. Stop Deadpool from ruining the party.


Just have a glance at the code, the comments are included to narrate what's going on -



 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
public class EnumDemo {
    
    public static void main(String[] args) {
        
        // This is a demo to show you how you can make use of the 'Superhero'
        // Enum
        
        // By default toString() method will be converting the enum variable
        // into String and displaying it, a case similar to Superman, who is not
        // interested in revealing his ID
        String selectedHero = Superhero.SUPERMAN.name();
        System.out.println("You selected - " + selectedHero);
        String realName = Superhero.SUPERMAN.toString();
        System.out.println("Real Name - " + realName + "\n");
        
        // While with Batman, it's not always the case, remember the Spoof "Do
        // you want to know my secret identity ??" ?, Hence a separate method
        // for such scenarios ;)
        String selectedHero2 = Superhero.BATMAN.name();
        System.out.println("You selected - " + selectedHero2);
        String realName2 = Superhero.BATMAN.toStringRevealRealName();
        System.out.println("Real Name - " + realName2);
        Superhero verify = Superhero.fromValue(realName2);
        System.out.println("ID verified, it's - " + verify.name() + "\n");
        
        // Now what is the advantage of using Enum? As you can see we have kind
        // of restricted the users with a given set of Superheroes, that means
        // Deadpool is not invited to the party... Check this out -
        String uninvitedGuest = "Wade Wilson";
        verify = Superhero.fromValue(uninvitedGuest);
        try {
            System.out.println("What do we get ? " + verify.name());
            } catch (Exception e) {
            System.out.println("Wade Wilson AKA Deadpool trying to sneak in...");
            System.out.println("Entry Allowed? " + e.getMessage());
        }
    }
    
}

enum Superhero {
    BATMAN("Bruce Wayne"), SUPERMAN("Clark Kent"), IRONMAN("Tony Stark"), SPIDERMAN("Peter Parker");
    
    private String value;
    
    Superhero(String value) {
        this.value = value;
    }
    
    public static Superhero fromValue(String str) {
        for (Superhero s: Superhero.values()) {
            if (String.valueOf(s.value).equalsIgnoreCase(str)) {
                return s;
            }
        }
        return null;
    }
    
    public String toStringRevealRealName() {
        return value;
    }
    
}


Well, after this action, here is the aftermath, I mean the logs -

You selected - SUPERMAN
Real Name - SUPERMAN

You selected - BATMAN
Real Name - Bruce Wayne
ID verified, it's - BATMAN

Wade Wilson AKA Deadpool trying to sneak in...
Entry Allowed? null

For full code/ project, visit -

https://github.com/namitsharma99/EnumDemoJava.git


So that's it for now. Will meet you soon with some other interesting topics.
Happy coding!







Data Structures and Algorithms | Complexity Analysis | Linear and Binary Search







When we write a code, many a times it happens that the functionality is met, but still the way the code runs with, doesn’t please the perfectionist developer inside us.

Those buddies who are well experienced with difficult stakeholders, clients or even interviewers, may know the pain, when someone says “Your code works fine, but still it doesn’t look efficient… “.

To avoid such encounters, it becomes crucial to emphasize on the complexity analysis of the algorithm, at the very early stages of the career. But as we always say, it's never too late to start a good practice.

So this time, we will use this post to go through OR revisit the concepts of ‘Complexity Analysis’.

And it is promised, that the following posts will try to dig a deeper insight in the ‘Data Structures And Algorithm’ arena.




How complexity is analysed?

There are N number of ways to do so, but the heroes that beat us often while writing the code are -
  1. Space Complexity
  2. Time Complexity

Disclaimer: The more you go inside these topics the more you will deviate towards the Maths you saw during Engineering :P

But we will stick to the useful take-aways that will help us in day-to-day coding and facing challenging problems.




Complexity here considers the memory the code is consuming and the time it is taking to process.




Space Complexity

With respect to JAVA, we can figure out how the memory management will be taking place while writing. What to consider here is -
1. Fixed consumption
The variables and constants defined during coding, being consumed for sure in the code path.
2. Variable consumption
The variables used for conditional assignments and calculations.




I would like to reflect the above with a small example here -

Consider the following snippet -

int a = 2;   // fixed 4 bytes
int b = 3; // fixed 4 bytes

if (a>b) {
return a;      // conditional 0 byte
} else {
int c = a*2 + c*3;
   // conditional
// allocates additional memory to store c
// and do the calculations
return c;
}


Cool Tip:
For more info, we can spend some time going through computer science books and learn how internal memory allocation works.





Time Complexity

This champ will be under the limelight if you are aiming at cracking IT giants, or want to mark your presence in various coding competitions.

It undertakes the compile and the process time, hence making us sure that the code works within the expected time limits.

So here the fixed factor is the ‘Compile Time’, and the variable one is ‘Process Time’.

I would like to share the 3 ways we can follow, which I read in a very good article long back, consolidated briefly, but unfortunately forgot the source.




1. Note the time, before the operation starts and after it ends. Get the difference and you get an idea of the time taken.

2. Do a dry run. I.e. grab a pen and paper, and execute the code step by step. This way you will consider all the loops and and iterations and get an idea on how effective your code is, is there any way to make it run better, are there any vague iterations, and so on.
A very helpful outcome of the point#2 strategy is that it makes you answerable well if you are asked by someone for N number of iterations.

For example,
When you are iterating N X N matrix, clearly you are involving 2 for loops.
Outer loop iteration 1 -> inner full iterations - N
Outer loop iteration 2 -> inner full iterations - N
Outer loop iteration 3 -> inner full iterations - N
.
. and so on...
.
Outer loop iteration N -> inner full iterations - N

Hence it takes N^2 steps.

But imagine if the number of iterations increase to millions or billions, you will be clever enough to not to start dry running with this much number. This is where point#3 comes to rescue.

3. Asymptotic Analysis.

Where your maths and calculus skills will be at stake. (Kidding, just do a smart work here and learn what exactly it tries to say!)
This analysis aims at giving an estimate about the code’s behavior, when number of iterations exceed manual control, and it comes in 3 flavors -

A. Big O Notation
Worst Case - when you get the result in the last step.
Upper Bound -
denoted as

                    f(n)=O(g(n))f(n)=O(g(n))

if and only if there exists constants k and n such that,

                    |f(x)|≤k|g(x)|∀x>n

B. Big Theta Notation
Average Case - what it generally takes on an average to get the result.
denoted as
                   
                    f(n)=θ(g(n))f(n)=θ(g(n))

if and only if there exists constants j,k and n such that,                   

                    j|g(x)|≤|f(x)|≤k|g(x)|∀x>n

C. Big Omega Notation
Best Case - when you get the result in first step.
denoted as

                    f(n)=Ω(g(n))f(n)=Ω(g(n))

if and only if there exists constants k and n such that,

                    |f(x)|≥k|g(x)|∀x>n
Thanks to this answer on Quora for sharing formulas, and making my life easier. LOL.




If you have time, check this out for how these actually are understood with the help of graphs.

So you can take away the following for now, if you are not having enough time to explore -

1. Use Big O in interviews and technical discussions, because no one will give you the best case scenario. Always prepare for the worst case scenario and hope for the best ;)
2. Big Theta is helpful to generalize an algo, using the average cases. Hence do some head banging on it whenever time allows you.
3. Big Omega is a dreamy concept, hence you can leave it for the last.




Moving on, as we have a custom here on TCB, we believe in demo and practicals more than the theory, so here we go.


Kicking off with the first step in Data Structures - Searching an element.


So broadly speaking we have 2 types of searches -

Unordered and Ordered.


Unordered -
That means no order is being followed in the elements’ placement, and for the very worst, you can assume that the element to be searched is at the end, and you are scanning from the beginning.
So If there are N elements, it requires N iterations and the operation would be of order O(N).


Ordered -
That means there is a logical order while placing the elements, either natural or alphabetical. 2 generally used ordered searches - Linear and Binary.

For Linear search, efficiency depends on the average number of steps taken i.e. if there are N elements, operation would be of O(N/2).

For Binary search also, the efficiency depends on the average number of steps taken, but since we are always having half of the steps remaining with each and every iteration, it introduces the overall function’s behavior as that of mathematical log function.
Hence it reflects as O(log2(N)).


To see how the search algorithms work feel free to drop by at some previously created blogs, just for you -







Now, let’s take a deep dive on the analysis of time taken.

Say time taken is directly dependent on the order of processing, hence in terms of equation it can be shown as:
T = K * log2(N).

To make it more clear on how steps can be realized, have a look at this example:

For 10 elements →  
The number of steps taken would be log2(10) ~= 3.322 ~= 4
Shortcut Tip:
Simply find the nearest power of 2 i.e. 2^3 = 8, but it’s lesser than 10, and we want to cover entire 10 elements. Hence 2^4 = 16 > 10, so 4 steps to cover 10 elements.

Similarly, for 100 elements → number of steps = log2(100) = 2*3.322 = 6.644 ~= 7 steps
Shortcut Tip:
Simply 2^6 = 64 < 100, hence 2^7 = 128 > 100, hence 7 steps to cover 100 elements... and so on...

Practice Tip:
Do some mathematical analysis on finding the number of steps taken. Once done with this, it won’t look much difficult.

Before leaving let’s have a quick look at some take aways -

Big O Notation - a rough measure of complexity
T:   time taken
N:  number of elements


1. Insert an element into an unordered array -

T = K (constant), since it is not dependent N. Complexity ~ O(1)

2. Performing a Linear Search

T = K * N/2. Complexity ~ O(N)

3. Performing Binary Search

T = K * log2(N). Complexity ~ O(log2(N))

4. For ordered array insert, delete, and unordered delete

Complexity ~ O(n)

And the rest is up to you. :)

You can dig as much as you want and do share your thoughts and feedback.
Those are always welcome and looked upon for making this place a better one for the coders.




Next series of blogs will be covering few more Data Structures’ concepts.




Cheers!!

Happy Coding.






















Featured post

Oracle SQL Scheduled Jobs - An Interesting Approach

  Oracle SQL Scheduled Jobs A DB Scheduler is the best way to automate any backend database job. For instance, if you want to process the p...