Comparing library version strings in Groovy - groovy

Let's say I have a following list of library's versions:
List myList = ["4.11", "4.12", "4.13", "5.1"]
I need to check if the first element of the list is equal to or greater than "4.11".
I do it this way:
#compateTo() returns 0 if the caller string equals to the argument string
#compateTo() returns > 0 if the caller string is greater than the argument string
if (myList[0].compareTo("4.11") >= 0) {
println("equal or greater than 4.11")
} else {
println("less than 4.11")
}
However, let's consider this case:
List myList = ["4.9"]
Comparing two strings character by character it gets to 9 compared to 1 and since 9 is greater than 1 it returns equal or greater than 4.11, which is incorrect.
What would be the best way to fix it? I considered this:
def strToDecimal = Double.parseDouble(myList[0])
to get a decimal number and compare two decimal numbers 4.9 and 4.11 but the problem is the same.
I cannot use anything that would require an import statement.

If you're using Java >= 9, I'd go with the Version class:
// List myList = ["4.11", "4.12", "4.13", "5.1"]
List myList = ["4.9"]
if (java.lang.module.ModuleDescriptor.Version.parse(myList[0]).compareTo(java.lang.module.ModuleDescriptor.Version.parse("4.11")) >= 0) {
println("equal or greater than 4.11")
} else {
println("less than 4.11")
}
If your Java version is <= 9, then you may checkout this question. There are some ideas on how to solve your problem.

Related

How to compare two decimals of different length Groovy [duplicate]

Let's say I have a following list of library's versions:
List myList = ["4.11", "4.12", "4.13", "5.1"]
I need to check if the first element of the list is equal to or greater than "4.11".
I do it this way:
#compateTo() returns 0 if the caller string equals to the argument string
#compateTo() returns > 0 if the caller string is greater than the argument string
if (myList[0].compareTo("4.11") >= 0) {
println("equal or greater than 4.11")
} else {
println("less than 4.11")
}
However, let's consider this case:
List myList = ["4.9"]
Comparing two strings character by character it gets to 9 compared to 1 and since 9 is greater than 1 it returns equal or greater than 4.11, which is incorrect.
What would be the best way to fix it? I considered this:
def strToDecimal = Double.parseDouble(myList[0])
to get a decimal number and compare two decimal numbers 4.9 and 4.11 but the problem is the same.
I cannot use anything that would require an import statement.
If you're using Java >= 9, I'd go with the Version class:
// List myList = ["4.11", "4.12", "4.13", "5.1"]
List myList = ["4.9"]
if (java.lang.module.ModuleDescriptor.Version.parse(myList[0]).compareTo(java.lang.module.ModuleDescriptor.Version.parse("4.11")) >= 0) {
println("equal or greater than 4.11")
} else {
println("less than 4.11")
}
If your Java version is <= 9, then you may checkout this question. There are some ideas on how to solve your problem.

Checking if the integer only contains odd number

I can't figure out what I'm doing wrong, but my solution seems to be not working.
Check that the given positive integer n contains only odd digits (1, 3, 5, 7 and 9) when it is written out. Return True if this is the case, and False otherwise. Note that this question is not asking whether the number n itself is odd or even. You therefore will have to look at every digit of the given number before you can proclaim that the number contains no odd digits.
My solution (for Python)
def only_odd_digits(n):
b = list(str(n))
onlyodd = [1,3,5,7,9]
for index, value in enumerate(b):
if value in onlyodd:
return True
else:
return False
Can someone help? Thanks
You can also use all to avoid the loops, and then use modulo as already suggested by alparslan mimaroğlu to avoid the lookup:
def only_odd_digits(n):
digits = map(int, str(n))
return all(dig % 2 for dig in digits)
I liked the set-based answer which got deleted now. It works when using it like this:
def only_odd_digits(n):
return set(str(n)).issubset(set("13579"))
You already created the list of integers you want to check.
You just have to check every digit if it is divisible by 2.
If any of them are you can just return False. If none of them are you can return True
def only_odd_digits(n):
digits = [int(digit) for digit in str(n)]
for digit in digits:
if digit % 2 == 0:
return False
return True
Use the following codes:
def odd(n):
return set(str(n))-set('13579')==set()

Finding the median of an array of floating point numbers

I've looked through all the examples in here already of this and nothing quite answers my question. I'm very new to Groovy.
I want to create something like a list or an array of floating point numbers, prices such as 239.99.
I then want to pass that array or list to a method that will determine the median price in that array or list of numbers. The total size will vary.
Is there any quick and easy code to do this? How do I add each number to the array or list and must I use doubles?
Any help is appreciated, this one has me stuck and frustrated.
Thanks!
The following function determines the median for non-empty lists.
def median(data) {
def copy = data.toSorted()
def middle = data.size().intdiv(2)
// you can omit the return in groovy for the last statement
data.size() % 2 ? copy[middle] : (copy[middle - 1] + copy[middle]) / 2
}
It works with all types that support addition and division.
For example:
assert median([1, 7, 4, 3]) == 3.5
assert median([1, 7, 4]) == 4
assert median([1, 7]) == 4
assert median([1]) == 1
assert median([1.7, 3.4, 10.9, 4.2]) == 3.8
In terms of what you can do with lists check the Lists overview and then the List API.

Algorithm for generating all string combinations

Say I have a list of strings, like so:
strings = ["abc", "def", "ghij"]
Note that the length of a string in the list can vary.
The way you generate a new string is to take one letter from each element of the list, in order. Examples: "adg" and "bfi", but not "dch" because the letters are not in the same order in which they appear in the list. So in this case where I know that there are only three elements in the list, I could fairly easily generate all possible combinations with a nested for loop structure, something like this:
for i in strings[0].length:
for ii in strings[1].length:
for iii in strings[2].length:
print(i+ii+iii)
The issue arises for me when I don't know how long the list of strings is going to be beforehand. If the list is n elements long, then my solution requires n for loops to succeed.
Can any one point me towards a relatively simple solution? I was thinking of a DFS based solution where I turn each letter into a node and creating a connection between all letters in adjacent strings, but this seems like too much effort.
In python, you would use itertools.product
eg.:
>>> for comb in itertools.product("abc", "def", "ghij"):
>>> print(''.join(comb))
adg
adh
adi
adj
aeg
aeh
...
Or, using an unpack:
>>> words = ["abc", "def", "ghij"]
>>> print('\n'.join(''.join(comb) for comb in itertools.product(*words)))
(same output)
The algorithm used by product is quite simple, as can be seen in its source code (Look particularly at function product_next). It basically enumerates all possible numbers in a mixed base system (where the multiplier for each digit position is the length of the corresponding word). A simple implementation which only works with strings and which does not implement the repeat keyword argument might be:
def product(words):
if words and all(len(w) for w in words):
indices = [0] * len(words)
while True:
# Change ''.join to tuple for a more accurate implementation
yield ''.join(w[indices[i]] for i, w in enumerate(words))
for i in range(len(indices), 0, -1):
if indices[i - 1] == len(words[i - 1]) - 1:
indices[i - 1] = 0
else:
indices[i - 1] += 1
break
else:
break
From your solution it seems that you need to have as many for loops as there are strings. For each character you generate in the final string, you need a for loop go through the list of possible characters. To do that you can make recursive solution. Every time you go one level deep in the recursion, you just run one for loop. You have as many level of recursion as there are strings.
Here is an example in python:
strings = ["abc", "def", "ghij"]
def rec(generated, k):
if k==len(strings):
print(generated)
return
for c in strings[k]:
rec(generated + c, k+1)
rec("", 0)
Here's how I would do it in Javascript (I assume that every string contains no duplicate characters):
function getPermutations(arr)
{
return getPermutationsHelper(arr, 0, "");
}
function getPermutationsHelper(arr, idx, prefix)
{
var foundInCurrent = [];
for(var i = 0; i < arr[idx].length; i++)
{
var str = prefix + arr[idx].charAt(i);
if(idx < arr.length - 1)
{
foundInCurrent = foundInCurrent.concat(getPermutationsHelper(arr, idx + 1, str));
}
else
{
foundInCurrent.push(str);
}
}
return foundInCurrent;
}
Basically, I'm using a recursive approach. My base case is when I have no more words left in my array, in which case I simply add prefix + c to my array for every c (character) in my last word.
Otherwise, I try each letter in the current word, and pass the prefix I've constructed on to the next word recursively.
For your example array, I got:
adg adh adi adj aeg aeh aei aej afg afh afi afj bdg bdh bdi
bdj beg beh bei bej bfg bfh bfi bfj cdg cdh cdi cdj ceg ceh
cei cej cfg cfh cfi cfj

groovy: how to simplify/rewrite this method in groovy

protected int xMethod (Integer a, Integer b) {
if (a<b)
return 1
else if (a>b)
return 2
else
return 3
}
I wonder if there is some way of rewriting above method differently in groovy? as now is very Java style.
It seems that the function just needs to return 3 different values depending on whether a is less than, equal to, or greater than b. There is already an operator in Groovy that does this:
a <=> b
The return values are -1, 0 and 1. Perhaps the best thing to do is refactor the code to use this operator instead of xMethod, if that is possible.
Of course, if the precise values 1, 2 and 3 are important and not just 3 distinct values then you can't do this.
Just to expand on Mark's answer:
protected int xMethod (Integer a, Integer b) {
switch ( a <=> b ) {
case -1: 1; break
case 1: 2; break
case 0: 3; break
}
}
However, you have to question whether this method has any value. If the caller can be changed to accept -1, 0, 1 then the method has no reason to exist.
How about:
return (a <=> b) + 2
If you remove the two occurrences of Integer from the signature, you can call the method with any parameters for which < is defined.
E.g.
assert x.xMethod(1, 2)==1
assert x.xMethod("2", "1")==2
assert x.xMethod(2.0, 2.0)==3

Resources