Need a code to make tree structure from version names - java

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();
}
}

Related

Java: Converting between bases with custom symbols

I was wondering if you can create a custom base with your own symbols instead of the one Java applies to you with Integer.parseInt (0-9 and A-P.)
I was thinking of something like this:
public class Base {
private String symbols;
public Base(String symbols) {
this.symbols = symbols;
}
// for example: new Base("0123456789"); would represent base 10
public static String convertBases(Base from, Base to, String toConvert) {
// Takes toConvert which is encoded in base "from" and converts it to base "to"
}
}
I am not sure how to implement this. Does anyone have the code for this?
To do this, you need to first parse the input text in the from base, then format the value in the to base, exactly like you'd need to do if using standard base "alphabet".
public static String convertBases(int fromRadix, int toRadix, String text) {
int value = Integer.parseInt(text, fromRadix);
return Integer.toString(value, toRadix);
}
So, first you implement parse and toString, then implementing convertTo is easy:
public class Base {
private final String symbols;
private final BigInteger radix;
private final Map<Character, Integer> symbolIndex;
public Base(String symbols) {
if (symbols.length() <= 1)
throw new IllegalArgumentException("Must provide at least 2 symbols: length=" + symbols.length());
this.symbols = symbols;
this.radix = BigInteger.valueOf(symbols.length());
this.symbolIndex = new HashMap<>(symbols.length() * 4 / 3 + 1);
for (int i = 0; i < symbols.length(); i++) {
Integer prevIndex = this.symbolIndex.putIfAbsent(symbols.charAt(i), i);
if (prevIndex != null)
throw new IllegalArgumentException("Duplicate symbol at index " + prevIndex +
" and " + i + ": " + symbols.charAt(i));
}
}
public BigInteger parse(String text) {
BigInteger value = BigInteger.ZERO;
for (int i = 0; i < text.length(); i++) {
Integer index = this.symbolIndex.get(text.charAt(i));
if (index == null)
throw new IllegalArgumentException("Not a valid number: " + text);
value = value.multiply(this.radix).add(BigInteger.valueOf(index));
}
return value;
}
public String toString(BigInteger value) {
if (value.signum() < 0)
throw new IllegalArgumentException("Negative value not allowed: " + value);
if (value.signum() == 0)
return this.symbols.substring(0, 1);
StringBuilder buf = new StringBuilder();
for (BigInteger v = value; v.signum() != 0; v = v.divide(this.radix))
buf.append(this.symbols.charAt(v.mod(this.radix).intValue()));
return buf.reverse().toString();
}
public String convertTo(Base newBase, String text) {
return newBase.toString(parse(text));
}
}
Test
Base base3 = new Base("012");
Base base6alpha = new Base("ABCDEF");
System.out.println(base3.convertTo(base6alpha, "0")); // 0 -> A
System.out.println(base3.convertTo(base6alpha, "2")); // 2 -> C
System.out.println(base3.convertTo(base6alpha, "10")); // 3 -> D
System.out.println(base3.convertTo(base6alpha, "200")); // 18 -> DA
Output
A
C
D
DA
Test 2
Base obscure = new Base("^JsdloYF9%");
Base base64 = new Base("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/");
BigInteger value = new BigInteger("123456789012345678901234567890"); // Too large for int and long
String obscureValue = obscure.toString(value);
String base64Value = base64.toString(value);
System.out.println(obscureValue);
System.out.println(base64Value);
System.out.println(base64.convertTo(obscure, base64Value));
System.out.println(obscure.convertTo(base64, obscureValue));
Output
JsdloYF9%^JsdloYF9%^JsdloYF9%^
BjukP9sNz4O5OPwrS
JsdloYF9%^JsdloYF9%^JsdloYF9%^
BjukP9sNz4O5OPwrS
Let's start with a value type. It holds a string representation and a Base object. (i.e., it has a string representation and a something like a decoder). Why? because we don't want to pass around Strings which we need to look at and "guess" what base they are.
public class CustomNumber {
private final String stringRepresentation;
private final Base base;
public CustomNumber(String stringRepresentation, Base base) {
super();
this.stringRepresentation = stringRepresentation;
this.base = base;
}
public long decimalValue() {
return base.toDecimal(stringRepresentation);
}
public CustomNumber toBase(Base newBase) {
long decimalValue = this.decimalValue();
String stringRep = newBase.fromDecimal(decimalValue);
return new CustomNumber(stringRep, newBase);
}
}
Then we need to define an interface which is broad enough to handle any regular or custom-symbol base. We will later build concrete implementations on top.
public interface Base {
public long toDecimal(String stringRepresentation);
public String fromDecimal(long decimalValue);
}
We are all set. Lets do an example implementation to support the standard decimal number format before going to custom string symbols:
public class StandardBaseLong implements Base{
public long toDecimal(String stringRepresentation) {
return Long.parseLong(stringRepresentation);
}
public String fromDecimal(long decimalValue) {
return Long.toString(decimalValue);
}
}
Now finally, coming to the custom string base:
public class CustomBase implements Base{
private String digits;
public CustomBase(String digits) {
this.digits = digits;
}
public long toDecimal(String stringRepresentation) {
//Write logic to interpret that string as your base
return 0L;
}
public String fromDecimal(long decimalValue) {
//Write logic to generate string output in your base format
return null;
}
}
Now you have a framework to work with various custom and standard bases.
Of course, there could be more customisations and improved features (more convenience constructors, hashCode and equals implementations and arithmetic). But, they are beyond the scope of this answer.

How to join a String array to a int array and sort by number (higher to lower) in Android?

I have two arrays:
int[] sinais = new int[arraySinais.length];
String[] arraySSID = new String[] { };
And I joined them into one array:
String[] arrayScan = new String[arraySinais.length];
for (int i = 0; i < arraySSID.length; i++) {
arrayScan[i] = arraySSID[i] + " " + sinais[i];
}
But now I need to sort this new array by numbers in a decreasing order and put an Image inside ListView depending the numbers, and I do not have any idea how to do this.
you can use create your own object which contains the int and the string and use arraylist to sort
First create your own custom Element (Object) which mainly consist of an int number and a String string.
public class Element implements Comparable<Element>{
private int number;
private String string;
public Element(String string, int number) {
this.number =number;
this.string = string;
}
//create custom constructors if its allowed to define an element without a number or string
public int getNumber() {
return number;
}
public void setNumber(int number) {
this.number = number;
}
public String getString() {
return string;
}
public void setString(String string) {
this.string = string;
}
#Override
public int compareTo(Element e) {
return number - e.number;
}
}
Implement comparable as above to sort depending on the number value, but keep in my mind that your element won't sort stand alone strings.
If you want to sort your list depending on strings if a number doesn't exist use this implementation of comparTo() method:
#Override
public int compareTo(Element e) {
if(e.number != 0) return number - e.number;
return string.compareTo(e.string);
}
While using implement a List of elements and use Collections sort() method and you are good to go:
List<Element> list = new ArrayList<>();
//add Elements
Collections.sort(list);
I used the method below, by Bubble Sort, and solve my problem:
> for (int i = Sinais.length; i >= 1; i--){
> for (int j = 1; j < i; j++){
> if (Sinais[j-1]<Sinais[j]){
> int aux = Sinais[j];
> String aux2 = ArraySSID[j];
> Sinais[j] = Sinais[j-1];
> ArraySSID[j] = ArraySSID[j-1];
> Sinais[j-1] = aux;
> ArraySSID[j-1] = aux2;
> }
> }
> }

Altering the value of k in kNN algorithm - Java

I have applied the KNN algorithm for classifying handwritten digits. the digits are in vector format initially 8*8, and stretched to form a vector 1*64..
As it stands my code applies the kNN algorithm but only using k = 1. I'm not entirely sure how to alter the value k after attempting a couple of things I kept getting thrown errors. If anyone could help push me in the right direction it would be really appreciated. The training dataset can be found here and the validation set here.
ImageMatrix.java
import java.util.*;
public class ImageMatrix {
private int[] data;
private int classCode;
private int curData;
public ImageMatrix(int[] data, int classCode) {
assert data.length == 64; //maximum array length of 64
this.data = data;
this.classCode = classCode;
}
public String toString() {
return "Class Code: " + classCode + " Data :" + Arrays.toString(data) + "\n"; //outputs readable
}
public int[] getData() {
return data;
}
public int getClassCode() {
return classCode;
}
public int getCurData() {
return curData;
}
}
ImageMatrixDB.java
import java.util.*;
import java.io.*;
import java.util.ArrayList;
public class ImageMatrixDB implements Iterable<ImageMatrix> {
private List<ImageMatrix> list = new ArrayList<ImageMatrix>();
public ImageMatrixDB load(String f) throws IOException {
try (
FileReader fr = new FileReader(f);
BufferedReader br = new BufferedReader(fr)) {
String line = null;
while((line = br.readLine()) != null) {
int lastComma = line.lastIndexOf(',');
int classCode = Integer.parseInt(line.substring(1 + lastComma));
int[] data = Arrays.stream(line.substring(0, lastComma).split(","))
.mapToInt(Integer::parseInt)
.toArray();
ImageMatrix matrix = new ImageMatrix(data, classCode); // Classcode->100% when 0 -> 0% when 1 - 9..
list.add(matrix);
}
}
return this;
}
public void printResults(){ //output results
for(ImageMatrix matrix: list){
System.out.println(matrix);
}
}
public Iterator<ImageMatrix> iterator() {
return this.list.iterator();
}
/// kNN implementation ///
public static int distance(int[] a, int[] b) {
int sum = 0;
for(int i = 0; i < a.length; i++) {
sum += (a[i] - b[i]) * (a[i] - b[i]);
}
return (int)Math.sqrt(sum);
}
public static int classify(ImageMatrixDB trainingSet, int[] curData) {
int label = 0, bestDistance = Integer.MAX_VALUE;
for(ImageMatrix matrix: trainingSet) {
int dist = distance(matrix.getData(), curData);
if(dist < bestDistance) {
bestDistance = dist;
label = matrix.getClassCode();
}
}
return label;
}
public int size() {
return list.size(); //returns size of the list
}
public static void main(String[] argv) throws IOException {
ImageMatrixDB trainingSet = new ImageMatrixDB();
ImageMatrixDB validationSet = new ImageMatrixDB();
trainingSet.load("cw2DataSet1.csv");
validationSet.load("cw2DataSet2.csv");
int numCorrect = 0;
for(ImageMatrix matrix:validationSet) {
if(classify(trainingSet, matrix.getData()) == matrix.getClassCode()) numCorrect++;
} //285 correct
System.out.println("Accuracy: " + (double)numCorrect / validationSet.size() * 100 + "%");
System.out.println();
}
In the for loop of classify you are trying to find the training example that is closest to a test point. You need to switch that with a code that finds K of the training points that is the closest to the test data. Then you should call getClassCode for each of those K points and find the majority(i.e. the most frequent) of the class codes among them. classify will then return the major class code you found.
You may break the ties (i.e. having 2+ most frequent class codes assigned to equal number of training data) in any way that suits your need.
I am really inexperienced in Java, but just by looking around the language reference, I came up with the implementation below.
public static int classify(ImageMatrixDB trainingSet, int[] curData, int k) {
int label = 0, bestDistance = Integer.MAX_VALUE;
int[][] distances = new int[trainingSet.size()][2];
int i=0;
// Place distances in an array to be sorted
for(ImageMatrix matrix: trainingSet) {
distances[i][0] = distance(matrix.getData(), curData);
distances[i][1] = matrix.getClassCode();
i++;
}
Arrays.sort(distances, (int[] lhs, int[] rhs) -> lhs[0]-rhs[0]);
// Find frequencies of each class code
i = 0;
Map<Integer,Integer> majorityMap;
majorityMap = new HashMap<Integer,Integer>();
while(i < k) {
if( majorityMap.containsKey( distances[i][1] ) ) {
int currentValue = majorityMap.get(distances[i][1]);
majorityMap.put(distances[i][1], currentValue + 1);
}
else {
majorityMap.put(distances[i][1], 1);
}
++i;
}
// Find the class code with the highest frequency
int maxVal = -1;
for (Entry<Integer, Integer> entry: majorityMap.entrySet()) {
int entryVal = entry.getValue();
if(entryVal > maxVal) {
maxVal = entryVal;
label = entry.getKey();
}
}
return label;
}
All you need to do is adding K as a parameter. Keep in mind, however, that the code above does not handle ties in a particular way.

How to find N grams of a word in Java?

For example if the input is "name" and the minGram is 1 and maxGramSize is 2 output will consist of n,a,m,e,na,am,me. If the minGram=2, maxGram=4 inputWord=name, output = na,am,me,nam,ame,name.
Function signature can be something like this:
public List<String> generateNGrams(String input, int minGramSize, int maxGramSize)
Initially I tried doing it with for loops, but I was finding it hard to follow the indices. Then I tried solving it using recursion with pen and paper but I'm still struggling with it. Can someone help me with this?
One solution:
private static void addNgrams(final int size, final String input,
final List<String> list)
{
final int maxStartIndex = input.length() - size;
for (int i = 0; i < maxStartIndex; i++)
list.add(input.stubString(i, i + size));
}
public List<String> generateNGrams(final String input, final int minSize,
final int maxSize)
{
final List<String> ret = new ArrayList<>();
for (int size = minSize; size <= maxSize; size++)
addNgrams(size, input, ret);
return ret;
}
Note: lacks basic error checkings (for instance, maxSize greater than the size of input; minSize greater than maxSize; others); left as an exercise.
Here is a program that recursively generates nGrams: This code also handles the tail grams.
import java.util.ArrayList;
public class NGrams {
ArrayList<String> nGrams = new ArrayList<String>();
public void generateNGrams(String str, int n) {
if (str.length() == n ) {
int counter = 0;
while (counter < n) {
nGrams.add(str.substring(counter));
counter++;
}
return;
}
int counter = 0;
String gram = "";
while (counter < n) {
gram += str.charAt(counter);
counter++;
}
nGrams.add(gram);
generateNGrams(str.substring(1), n);
}
public void printNGrams() {
for (String str : nGrams) {
System.out.println(str);
}
}
public static void main(String[] args) {
NGrams ng = new NGrams();
ng.generateNGrams("hello world", 3);
ng.printNGrams();
}
}
Output:
hel
ell
llo
lo
o w
wo
wor
orl
rld
ld
d

Getting Max value from x.y.z formatted Number

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.

Categories