Simple ranking algorithm in Groovy - algorithm

I have a short groovy algorithm for assigning rankings to food based on their rating. This can be run in the groovy console. The code works perfectly, but I'm wondering if there is a more Groovy or functional way of writing the code. Thinking it would be nice to get rid of the previousItem and rank local variables if possible.
def food = [
[name:'Chocolate Brownie',rating:5.5, rank:null],
[name:'Fudge', rating:2.1, rank:null],
[name:'Pizza',rating:3.4, rank:null],
[name:'Icecream', rating:2.1, rank:null],
[name:'Cabbage', rating:1.4, rank:null]]
food.sort { -it.rating }
def previousItem = food[0]
def rank = 1
previousItem.rank = rank
food.each { item ->
if (item.rating == previousItem.rating) {
item.rank = previousItem.rank
} else {
item.rank = rank
}
previousItem = item
rank++
}
assert food[0].rank == 1
assert food[1].rank == 2
assert food[2].rank == 3
assert food[3].rank == 3 // Note same rating = same rank
assert food[4].rank == 5 // Note, 4 skipped as we have two at rank 3
Suggestions?

This is my solution:
def rank = 1
def groupedByRating = food.groupBy { -it.rating }
groupedByRating.sort().each { rating, items ->
items.each { it.rank = rank }
rank += items.size()
}

I didn't try it, but maybe this could work.
food.eachWithIndex { item, i ->
if( i>0 && food[i-1].rating == item.rating )
item.rank = food[i-1].rank
else
item.rank = i + 1
}

Here's another alternative that doesn't use "local defs" with the groovy inject method:
food.sort { -it.rating }.inject([index: 0]) { map, current ->
current.rank = (current.rating == map.lastRating ? map.lastRank : map.index + 1)
[ lastRating: current.rating, lastRank: current.rank, index: map.index + 1 ]
}

Related

How to ensure minimum occurrences of RNG outcomes?

I'm working on a basic password generator for This Reddit Programming Exercise. I have very simple password generation working in Kotlin, but I'm struggling to come up with a good way to guarantee a specific minimum number of each character type (i.e. at least 2 each of Upper, Lower, Digit, and special character).
I could easily just do two of each to start the password, but I want them to be randomly distributed, not all front-loaded. I also thought of inserting the characters randomly into a character array, rather than appending to a string, but I was wondering if maybe there is a better way.
Here is what I have currently:
private fun generatePassword() {
var password = ""
val passwordLength = (8..25).random()
for (i in 0..passwordLength) {
val charType = (1..5).random()
when (charType) {
1 -> password += lettersLower[(0..lettersLower.size).random()]
2 -> password += lettersUpper[(0..lettersUpper.size).random()]
3 -> password += numbers[(0..numbers.size).random()]
4 -> password += symbols[(0..symbols.size).random()]
}
}
println(password)
}
This works and generates a random password of a random length of 8-24 characters, and contains a random combination of uppercase letters, lowercase letters, digits, and special characters, but it doesn't guarantee the presence of any specific number of each type, like most websites require nowadays.
I thought of doing something like this:
private fun generatePassword() {
var password: ArrayList<Char> = arrayListOf()
var newChar:Char
var numLow = 0
var numUpp = 0
var numDig = 0
var numSpe = 0
while (numLow < 2){
newChar = lettersLower[(0..lettersLower.size).random()]
password.add((0..password.size).random(), newChar)
numLow++
}
while (numUpp < 2){
newChar = lettersUpper[(0..lettersUpper.size).random()]
password.add((0..password.size).random(), newChar)
numUpp++
}
while (numDig < 2){
newChar = numbers[(0..numbers.size).random()]
password.add((0..password.size).random(), newChar)
numDig++
}
while (numSpe < 2){
newChar = symbols[(0..symbols.size).random()]
password.add((0..password.size).random(), newChar)
numSpe++
}
val passwordLength = (8..25).random() - password.size
for (i in 0..passwordLength) {
val charType = (1..5).random()
when (charType) {
1 -> {
newChar = lettersLower[(0..lettersLower.size).random()]
password.add(newChar)
}
2 -> {
newChar = lettersUpper[(0..lettersUpper.size).random()]
password.add(newChar)
}
3 -> {
newChar = numbers[(0..numbers.size).random()]
password.add(newChar)
}
4 -> {
newChar = symbols[(0..symbols.size).random()]
password.add(newChar)
}
}
}
for (i in password.indices){
print(password[i])
}
print("\n")
}
But that doesn't seem particularly concise. The other option I thought of is to check if the password contains two of each type of character and generate a new one if it doesn't, but that seems awfully inefficient. Is there a better way to ensure that if I run my RNG 8+ times it will return at least, but not exactly, two ones, two twos, two threes, and two fours?
Here's my random function, if that helps:
// Random function via SO user #s1m0nw1 (https://stackoverflow.com/a/49507413)
private fun ClosedRange<Int>.random() = (Math.random() * (endInclusive - start) + start).toInt()
I also found this SO post in Java, but it's also not very concise and I'm wondering if there is a more general purpose, more concise solution to ensure a minimum number of occurrences for each possible outcome of an RNG over a number of trials greater than the sum of those minimum occurrences.
Sorry for the rambling post. Thanks in advance for your insight.
I think your second version is on the right track. It can be simplified to:
import java.util.Random
fun generatePassword() : String {
// this defines the classes of characters
// and their corresponding minimum occurrences
val charClasses = arrayOf(
('a'..'z').asIterable().toList() to 2,
('A'..'Z').asIterable().toList() to 2,
('0'..'9').asIterable().toList() to 2,
"!##$%^&*()_+".asIterable().toList() to 2
)
val maxLen = 24;
val minLen = 8;
var password = StringBuilder()
val random = Random()
charClasses.forEach {(chars, minOccur) ->
(0..minOccur).forEach {
password.insert(
if (password.isEmpty()) 0 else random.nextInt(password.length),
chars[random.nextInt(chars.size)])
}
}
((password.length + 1)..(random.nextInt(maxLen - minLen + 1) + minLen)).forEach {
val selected = charClasses[random.nextInt(charClasses.size)]
password.append(selected.first[random.nextInt(selected.first.size)])
}
return password.toString()
}

Scala/functional/without libs - check if string permutation of other

How could you check to see if one string is a permutation of another using scala/functional programming with out complex pre-built functions like sorted()?
I'm a Python dev and what I think trips me up the most is that you can't just iterate through a dictionary of character counts comparing to another dictionary of character counts, then just exit when there isn't a match, you can't just call break.
Assume this is the starting point, based on your description:
val a = "aaacddba"
val b = "aabaacdd"
def counts(s: String) = s.groupBy(identity).mapValues(_.size)
val aCounts = counts(a)
val bCounts = counts(b)
This is the simplest way:
aCounts == bCounts // true
This is precisely what you described:
def isPerm(aCounts: Map[Char,Int], bCounts: Map[Char,Int]): Boolean = {
if (aCounts.size != bCounts.size)
return false
for ((k,v) <- aCounts) {
if (bCounts.getOrElse(k, 0) != v)
return false
}
return true
}
This is your method, but more scala-ish. (It also breaks as soon as a mismatch is found, because of how foreach is implemented):
(aCounts.size == bCounts.size) &&
aCounts.forall { case (k,v) => bCounts.getOrElse(k, 0) == v }
(Also, Scala does have break.)
Also, also: you should read the answer to this question.
Another option using recursive function, which will also 'break' immediately once mismatch is detected:
import scala.annotation.tailrec
#tailrec
def isPerm1(a: String, b: String): Boolean = {
if (a.length == b.length) {
a.headOption match {
case Some(c) =>
val i = b.indexOf(c)
if (i >= 0) {
isPerm1(a.tail, b.substring(0, i) + b.substring(i + 1))
} else {
false
}
case None => true
}
} else {
false
}
}
Out of my own curiosity I also create two more versions which use char counts map for matching:
def isPerm2(a: String, b: String): Boolean = {
val cntsA = a.groupBy(identity).mapValues(_.size)
val cntsB = b.groupBy(identity).mapValues(_.size)
cntsA == cntsB
}
and
def isPerm3(a: String, b: String): Boolean = {
val cntsA = a.groupBy(identity).mapValues(_.size)
val cntsB = b.groupBy(identity).mapValues(_.size)
(cntsA == cntsB) && cntsA.forall { case (k, v) => cntsB.getOrElse(k, 0) == v }
}
and roughly compare their performance by:
def time[R](block: => R): R = {
val t0 = System.nanoTime()
val result = block // call-by-name
val t1 = System.nanoTime()
println("Elapsed time: " + (t1 - t0) + "ns")
result
}
// Match
time((1 to 10000).foreach(_ => isPerm1("apple"*100,"elppa"*100)))
time((1 to 10000).foreach(_ => isPerm2("apple"*100,"elppa"*100)))
time((1 to 10000).foreach(_ => isPerm3("apple"*100,"elppa"*100)))
// Mismatch
time((1 to 10000).foreach(_ => isPerm1("xpple"*100,"elppa"*100)))
time((1 to 10000).foreach(_ => isPerm2("xpple"*100,"elppa"*100)))
time((1 to 10000).foreach(_ => isPerm3("xpple"*100,"elppa"*100)))
and the result is:
Match cases
isPerm1 = 2337999406ns
isPerm2 = 383375133ns
isPerm3 = 382514833ns
Mismatch cases
isPerm1 = 29573489ns
isPerm2 = 381622225ns
isPerm3 = 417863227ns
As can be expected, the char counts map speeds up positive cases but can slow down negative cases (overhead on building the char counts map).

Sort array by filename in groovy

I'm trying to sort a list of jars by their filenames:
def jars = ['app-5.0.0.jar', 'app-5.1.1.jar', 'app-5.2.0-9.jar', 'app-5.2.0-10.jar', 'app-5.2.0.jar', 'app-5.1.0.jar']
jars = jars.sort().reverse()
println jars
The result is:
[app-5.2.0.jar, app-5.2.0-9.jar, app-5.2.0-10.jar, app-5.1.1.jar, app-5.1.0.jar, app-5.0.0.jar]
However, I'm more interested in the natural (and probably more intuitive) sorting to receive this sorted list:
[app-5.2.0-10.jar, app-5.2.0-9.jar, app-5.2.0.jar, app-5.1.1.jar, app-5.1.0.jar, app-5.0.0.jar]
Is there a way to achieve this?
this is my current algorithm for sorting but it's too verbose in my opinion. However, it really does what I'm looking for. Each part of the version (major, minor, maintenance, build) is evaluated independently:
jars = jars.sort { a, b ->
File fileA = new File(a)
File fileB = new File(b)
def partsA = fileA.name.findAll(/\d+/)
def partsB = fileB.name.findAll(/\d+/)
if (partsA[0] == null) partsA[0] = "0"
if (partsB[0] == null) partsB[0] = "0"
if (partsA[0].toInteger() < partsB[0].toInteger()) {
println "${partsA[0]} < ${partsB[0]}"
return -1
} else if (partsA[0].toInteger() > partsB[0].toInteger()) {
println "${partsA[0]} > ${partsB[0]}"
return 1
} else {
if (partsA[1] == null) partsA[1] = "0"
if (partsB[1] == null) partsB[1] = "0"
if (partsA[1].toInteger() < partsB[1].toInteger()) {
println "${partsA[1]} < ${partsB[1]}"
return -1
} else if (partsA[1].toInteger() > partsB[1].toInteger()) {
println "${partsA[1]} > ${partsB[1]}"
return 1
} else {
if (partsA[2] == null) partsA[2] = "0"
if (partsB[2] == null) partsB[2] = "0"
if (partsA[2].toInteger() < partsB[2].toInteger()) {
println "${partsA[2]} < ${partsB[2]}"
return -1
} else if (partsA[2].toInteger() > partsB[2].toInteger()) {
println "${partsA[2]} > ${partsB[2]}"
return 1
} else {
if (partsA[3] == null) partsA[3] = "0"
if (partsB[3] == null) partsB[3] = "0"
if (partsA[3].toInteger() < partsB[3].toInteger()) {
println "${partsA[3]} < ${partsB[3]}"
return -1
} else if (partsA[3].toInteger() > partsB[3].toInteger()) {
println "${partsA[3]} > ${partsB[3]}"
return 1
} else {
println "${partsA[3]} = ${partsB[3]}"
return 0
}
}
}
}
}
Had to try this:
def jars = ['app-5.0.0.jar', 'app-5.1.1.jar', 'app-5.2.0-9.jar', 'app-5.2.0-10.jar', 'app-5.2.0.jar', 'app-5.1.0.jar', 'app-1.0.jar', 'app-0.10.jar']
jars = jars.sort{ -it.findAll( /\d+/ ).join().toInteger() }
println jars
Gets:
[app-5.2.0-10.jar, app-5.2.0-9.jar, app-5.2.0.jar, app-5.1.1.jar, app-5.1.0.jar, app-5.0.0.jar, app-1.0.jar, app-0.10.jar]
Or more thorough version that handles large patch versions:
def jars = ['app-5.0.0.jar', 'app-5.1.1.jar', 'app-5.2.0-9.jar', 'app-5.2.0-10.jar', 'app-5.2.0.jar', 'app-5.1.0.jar', 'app-5.1.1-172.jar']
jars.sort{ a, b ->
def aList = a.findAll(/\d+/)
def bList = b.findAll(/\d+/)
for ( int i = 0 ; i < aList.size() ; i++ ) {
def aVal = aList[i] ? aList[i].toInteger() : 0
def bVal = bList[i] ? bList[i].toInteger() : 0
if ( aVal <=> bVal ) { // only return if non-zero i.e. not equal
return aVal <=> bVal
}
}
bList.size() > aList.size() ? -1 : 0 // all facets match up to now, if b has additional parts it must be later version
}
println jars.reverse()
Gets:
[app-5.2.0-10.jar, app-5.2.0-9.jar, app-5.2.0.jar, app-5.1.1-172.jar, app-5.1.1.jar, app-5.1.0.jar, app-5.0.0.jar]
How about something like this:
def jars = ['app-5.0.0.jar', 'app-5.1.1.jar', 'app-5.2.0-9.jar', 'app-5.2.0-10.jar', 'app-5.2.0.jar', 'app-5.1.0.jar', 'app-5.1.1-172.jar']
// it is probably sufficient to just choose a "high enough" number
// (e.g. 10) instead of resolving max digits.
def maxDigits = jars*.findAll(/\d+/).flatten()*.size().max()
// sort the strings consisting of left-padded version numbers
// e.g. sorting string for 'app-5.1.1-172.jar' is ' 5 1 1172'
jars.sort{ it.findAll(/\d+/)*.padLeft(maxDigits).join() }
println 'max digits: ' + maxDigits
println jars.reverse()
Output:
max digits: 3
[app-5.2.0-10.jar, app-5.2.0-9.jar, app-5.2.0.jar, app-5.1.1-172.jar, app-5.1.1.jar, app-5.1.0.jar, app-5.0.0.jar]

Lua - how to sort a table by the value chain

I'm looking for a method of sorting a Lua table by its values chain. Say, the table:
local vals = {
{ id = "checkpoint4" },
{ id = "checkpoint1", nextid = "checkpoint2" },
{ id = "checkpoint3", nextid = "checkpoint4" },
{ id = "checkpoint2", nextid = "checkpoint3" },
}
Should transform into this after sorting:
local vals = {
{ id = "checkpoint1", nextid = "checkpoint2" },
{ id = "checkpoint2", nextid = "checkpoint3" },
{ id = "checkpoint3", nextid = "checkpoint4" },
{ id = "checkpoint4" },
}
It's not essentially with the exact same names, they might vary. I wanted to make the comparison of numbers after "checkpoint", but it turned out that I have to work with dynamic things like this (already sorted the way I want it to be):
local vals = {
{ id = "checkpoint1", nextid = "cp" },
{ id = "cp", nextid = "chp" },
{ id = "chp", nextid = "mynextcheckpoint" },
{ id = "mynextcheckpoint"},
}
Thanks.
What you are describing is called topological sorting. However, since this is a restricted case, we do not have to implement a complete topological sorting algorithm:
function sort_list(tbl)
local preceding = {}
local ending
local sorted = {}
for i, e in ipairs(tbl) do
if e.nextid == nil then
ending = e
else
preceding[e.nextid] = i
end
end
if ending == nil then
return nil, "no ending"
end
local j = #tbl
while ending ~= nil do
sorted[j] = ending
ending = tbl[preceding[ending.id]]
j = j - 1
end
if sorted[1] == nil then
return nil, "incomplete list"
end
return sorted
end
Usage:
local sorted = sort_list(vals)
local id2val, tailsizes = {}, {}
for _, val in ipairs(vals) do id2val[val.id] = val end
local function tailsize(val) -- memoized calculation of tails sizes
if not tailsizes[val] then
tailsizes[val] = 0 -- cycle-proof
if val.nextid and id2val[val.nextid] then -- dangling nextid proof
tailsizes[val] = tailsize(id2val[val.nextid]) + 1
end
end
return tailsizes[val]
end
-- sorting according to tails sizes
table.sort(vals, function(a,b) return tailsize(a) > tailsize(b) end)

removing nesting of if statements

I have a piece of code, which I am not sure how to refactor.. It is not very readable and I would like to make it readable. Here is a the problem
There are two columns in database which can be either NULL, 0 or have a value each. On the web page there is a checkbox - enable and text box - value for each of those two columns.
x = checkbox1
z = textbox1
y = checkbox2
w = textbox2
The logic is if both the checkboxes are not selected, then both the values should be 0. If either one is selected and other is not, then others value should be NULL. and for the one that is selected, if the textbox is empty its value should be NULL else should be the value in the textbox
if{x}
{
if(z)
{
a = NULL;
}
else
{
a = z;
}
if(y)
{
if(w)
{
b=w;
}
else
{
b = NULL;
}
}
else
{
b = null
}
}
else
{
if(y)
{
a = NULL;
if(w)
{
b=w;
}
else
{
b = NULL;
}
}
else
{
a = 0;
b = 0;
}
}
Trust me this is a valid scenario. Let me know if this makes sense or I should give more information
Using some logical ands and nots, we get something more readable.
We can save a little by defaulting to NULL (thus not needing to set the other to NULL). We can also save by putting the code for checking if a textbox is set or using null into a little function.
In pseudo code:
a = NULL
b = NULL
if (not checkbox1) and (not checkbox2):
a = 0
b = 0
if (checkbox1):
a = valueornull(textbox1)
if (checkbox2):
b = valueornull(textbox2)
function valueornull(textbox):
if textbox value:
return value
else:
return null
I think it would help to use more descriptive names that the single letters here, but assuming this is C code, it looks a lot neater with inline if statements:
if(x)
{
a = z ? NULL : z;
b = (y && w) ? w : NULL;
}
else
{
a = y ? NULL : 0;
b = (y && w) ? w : 0;
}

Resources