I would like to translate to C# the following Groovy code
def find_perfect_numbers(def number) {
(2..number).findAll { x-> (1..(x/2)).findAll{ x % it == 0 }.sum() == x }
}
which I got from here.
This is what I have, but it's not ready yet, doesn't compile either. I don't understand the groovy code good enough.
public List<int> find_perfect_numbers(int number)
{
List<int> lst = new List<int>();
lst = 2.To(number).FindAll(x => (1.To(x/2)).FindAll( x % it == 0).Sum() == x);
return lst;
}
I can't translate the part x % it == 0 (because "it" is an index).
I want the C# code to look as much like the groovy function as possible. Specifically, the line lst = 2.To( .....
I don't want to use a different solution to find perfect numbers (I have another working function already). For me this is only about the syntax, not about a good "perfect numbers function".
It's OK to create new (extension) functions that help doing this, just like the To function I used:
For the To function above I have used this StackOverflow function:
Generating sets of integers in C#
and changed it a little so that it returns a List of int instead of an array of int
public static class ListExtensions
{
public static List<int> To(this int start, int end)
{
return Enumerable.Range(start, end - start + 1).ToList();
}
}
Can anyone help me?
=== Update ===
This is what I have now, but it's not working yet, I get
DivideByZeroException was unhandled at the part s.value % s.idx == 0:
lst = 2.To(number).FindAll(x => ((1.To(x / 2)).Select((y, index) => new {value = y, idx = index}).Where( s => s.value % s.idx == 0).Sum(t => t.value) == (decimal)x));
I found it myself.
lst = 2.To(number)
.FindAll(x => ((1.To(x / 2))
.Select((y, index) => new {value = y, idx = index+1})
.Where( s => x % s.idx == 0)
.Sum(t => t.value) == (decimal)x));
Not as pretty as the Groovy one, but it works.
Related
I am new to groovy and trying to find the indexes of all sublists in a list.
I am trying to use something like Collections.indexOfSubList like in java but it gives exception saying it applies on Lists and not ArrayLists.
So I am trying to define my own function. I am finding all the indices of all the elements in the smaller list existing in the longer list and then subtracting the indices of the result array. If it comes to 1 then I am considering that index to a sublist.
I know that I have the logic a little twisted. Can somebody guide with a better and efficient way of doing this.
Below is my code:
List list1 = [1,2,3,4,5,6,1,2,3]
List list2 = [1,2]
index1 = list1.findIndexValues {
it == list2[0];
}
index2 = list1.findIndexValues {
it == list2[1];
}
println index1
println index2
result = []
for (int i = 0; i < index1.size(); i++) {
result.add(index2[i]-index1[i]);
}
println result
Edit: no longer uses Collections due to new issue re: Elastic Search.
The following code traverses along the source list, creating a sublist. It checks the sublist to see if it starts with the target list. See the asserts below (e.g. the indexes are 0-based):
def listStartsWithSubList = { source, target ->
def result = false
if (source.size() >= target.size()) {
result = true
target.eachWithIndex { item, index ->
result = result && (item == source[index])
}
}
result
}
def indexOfSubLists = { source, target ->
def results = []
source.eachWithIndex { item, index ->
def tmpList = source[index..source.size()-1]
if (listStartsWithSubList(tmpList, target)) {
results << index
}
}
results
}
assert [1] == indexOfSubLists([1,2,3], [2,3])
assert [2] == indexOfSubLists([1,2,3], [3])
assert [] == indexOfSubLists([1,2,3], [4])
assert [0,6] == indexOfSubLists([1,2,3,4,5,6,1,2,3], [1,2])
All is in the title, and the code is here:
implicit class utils(val chaîne: String) {
def permutations1(): List[String] = {
if (chaîne.length() == 0) List()
else
if (chaîne.length() == 1) List(chaîne)
else {
val retour1=for {i:Int <- 0 to chaîne.length() - 2
chaîne_réduite = chaîne.drop(i)
liste_avec_chaîne_réduite = chaîne_réduite.permutations1()
une_chaîne_réduite_et_permutée <- liste_avec_chaîne_réduite
j <- 0 to une_chaîne_réduite_et_permutée.length()
}
yield new StringBuilder(une_chaîne_réduite_et_permutée).insert(j, chaîne(j)).toString
retour1.toList
}
}
}
Can you explain me why it does not work and eventually correct my code to make it avoid the stack overflow?
Isn't the problem NP-complete? Thus you may only run any code with very limited length of strings.
To make it work on a reasonable string lengths careful optimization is required. For instance, to improve the performance you may try #tailrec optimization.
Representation in the form of String and StringBuilder is very inefficient for the task. Try List of Char for instance.
I found an answer myself:
implicit class utils (val chaîne: String) {
def permutations1 : Seq [String] = {
if (chaîne.size == 1) Seq (chaîne)
else chaîne.flatMap (x => chaîne.filterNot (_ == x).permutations1.map (x + _))
}
}
I am trying to find the difference between values in two maps
#Test
void testCollecEntries() {
def mapOne= ["A":900,"B":2000,"C":1500]
def maptwo = ["A":1000,"D":1500,"B":1500]
def balanceMap = maptwo.collectEntries { key, value-> [key:value-mapOne[key]] }
println balanceMap
}
I am trying to find the difference of values from maptwo with that of the values from mapOne. If the entry doesn't exist i need to ignore. This gives me a null pointer exception.
Appreciate any help.
It will throw NPE because you are looking for key "D" in mapOne which is not available.
You can avoid that by a null safe operation and default value to 0.
def one= [A:900, B:2000, C:1500]
def two = [A:1000, D:1500, B:1500]
def result = two.collectEntries{k,v -> [k, (v - (one[k]?:0))]}
println result
//Print
[A:100, D:1500, B:-500]
In case, you want to consider the common keys then use:
def result = two.collectEntries{k,v -> one[k] ? [k, (v - one[k])] : [:]}
//or
//def result = two.collectEntries{k,v -> (k in one.keySet()) ? [k, (v - one[k])] : [:]}
//Print
[A:100, B:-500]
You could look at this good example: http://groovyconsole.appspot.com/script/364002
I have an array and i want to build a map out of it recording the frequency of elements in the array. So for the example below the map = [15:2, 16:1] is what it will look like. How do I do this in Groovy ?
static void doSomething()
{
def a = [15,16,15]
def map = []
a.each{
k,v->
if(map.contains(it))
map.putAt k, v++
else
map.putAt k, 1;
}
println map
}
In Groovy 1.8 or higher,
assert [15, 16, 15].countBy { it } == [15: 2, 16: 1]
You could modify your code to be the following:
void doSomething() {
def a = [15,16,15]
def map = [:] //1
a.each { //2
if(map.containsKey(it)) map[it] = map[it] + 1 //3
else map[it] = 1;
}
println map
}
This fixes a few things:
map needs to be initiated with colon between braces, as notes by Bill James in comments.
can't use a 2-parameter version of each on an arraylist
postfix increment won't result in incremented value being saved; Also, explicit putAt call is fine, but it's there to provide the overloaded [key] = val syntax which is more expressive.
All that said, I'm assuming this is a coding exercise to learn groovy. doelleri's answer is more succinct and uses the tools provided, so in a real-world situation, I'd go with that.
I have the following code, which works, but I'm wondering if there is a "groovier" way of doing this:
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
* */
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
def part1 = isbn.substring(0, 1)
def part2 = isbn.substring(1, 7)
def part3 = isbn.substring(7, 9)
def part4 = isbn.substring(9, 10)
return "${part1}-${part2}-${part3}-${part4}"
} else if (isbn?.length() == 13) {
def part1 = isbn.substring(0, 3)
def part2 = isbn.substring(3, 4)
def part3 = isbn.substring(4, 10)
def part4 = isbn.substring(10, 12)
def part5 = isbn.substring(12, 13)
return "${part1}-${part2}-${part3}-${part4}-${part5}"
} else {
return isbn
}
}
You could first use the [] string operator to get the substrings instead of substring and drop the intermediate variables. For example in the case for length == 10:
"${isbn[0]}-${isbn[1..6]}-${isbn[7..8]}-${isbn[9]}"
Now, there is a bit of repetition there. You can get instead first get all the isbn segments and then .join them with '-':
[isbn[0], isbn[1..6], isbn[7..8], isbn[9]].join('-')
And, even further, instead of referencing isbn every time, you can make a list of the ranges you want to get and then get them all the same time using collect:
[0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
If you're going for code golfing, you can also do:
('-'+isbn)[1, 0, 2..7, 0, 8..9, 0, 10]
I'll leave it to you to figure out how that works, but i guess it's probably not a good idea to leave that on production code, unless you want to surprise future maintainers hehe.
Also, notice that the format when length == 13 is the same as for length == 10 but with a different prefix, you can then reuse the same function in that case. The whole function (with a couple of tests) would be:
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
**/
def formatIsbn(isbn) {
switch (isbn?.length()) {
case 10: return [0, 1..6, 7..8, 9].collect { isbn[it] }.join('-')
case 13: return isbn.take(3) + '-' + formatIsbn(isbn.drop(3))
default: return isbn
}
}
assert formatIsbn('abcdefghij') == 'a-bcdefg-hi-j'
assert formatIsbn('abcdefghijklm') == 'abc-d-efghij-kl-m'
Now, i think there are some bad smells in that code. Can isbn be null? At least to me, this doesn't look like a function that needs to bother about the nullity of its argument, or at least that's not clear by reading its name (it should be called something like formatIsbnOrNull instead if both ISBN strings and null values are accepted). If null values are not valid, then let it blow up with a NullPointerException when accessing isbn.length() so the caller know they have passed a wrong argument, instead of silently returning the same null.
The same goes for the return ISBN at the end. Is it expected for that function to receive a string that's neither 10 nor 13 characters long? If not, better throw new IllegalArgumentException() and let the caller know they have called it wrongly.
Finally, i'm not sure if this is the most "readable" solution. Another possible solution is having a string for the format, like '###-#-######-##-#' and then replace the #s by the isbn characters. I think it might be more self-documenting:
def formatIsbn(isbn) {
def format = [
10: '#-######-##-#',
13: '###-#-######-##-#'
][isbn.length()]
def n = 0
format.replaceAll(/#/) { isbn[n++] }
}
Consider adding the method to the String class, as shown here. Note that this answer is a spin on a clever suggestion in epidemian's answer (re: collect).
Note:
This code augments String with asIsbn().
The range [0..2] does not need the call to asIsbn(), but the symmetry of using collect twice is irresistable.
Groovy returns the last expression in if/else, so 'return' is not necessary
/**
* 10 digit - #-######-##-#
* 13 digit - ###-#-######-##-#
**/
String.metaClass.asIsbn = { ->
if (delegate.length() == 10) {
[0, 1..6, 7..8, 9].collect { delegate[it] }.join('-')
} else if (delegate.length() == 13) {
[0..2, 3..12].collect { delegate[it].asIsbn() }.join('-')
} else {
delegate
}
}
assert "abcdefghij".asIsbn() == 'a-bcdefg-hi-j'
assert "abcdefghijklm".asIsbn() == 'abc-d-efghij-kl-m'
assert "def".asIsbn() == "def"
String s = null
assert s?.asIsbn() == null
I would try using Regex... I think it's pretty much readable if you know how to use regex, and it's javascript inspired syntax in groovy is pretty cool also.
One more thing: it's pretty clear, looking at the capture groups, what your string looks like for the desired formatting.
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
m = isbn =~ /(\d{1})(\d{6})(\d{2})(\d{1})/
return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}"
} else if (isbn?.length() == 13) {
m = isbn =~ /(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/
return "${m[0][1]}-${m[0][2]}-${m[0][3]}-${m[0][4]}-${m[0][5]}"
} else {
return isbn
}
}
Btw, #epidemian suggestion using backreferences is great! I think the code would look like:
private formatISBN(String isbn) {
if (isbn?.length() == 10) {
return isbn.replaceAll(/(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4')
} else if (isbn?.length() == 13) {
return isbn.replaceAll(/(\d{3})(\d{1})(\d{6})(\d{2})(\d{1})/, '$1-$2-$3-$4-$5')
} else {
return isbn
}
}
Dunno if I like this any better. I'd make the position map a static final, too.
private isbnify(String isbn) {
def dashesAt = [ 10: [[0,1], [1,7], [7,9], [9,10]],
13: [[0,3], [3,4], [4,10], [10,12], [12,13]]]
def dashes = dashesAt[isbn?.length()]
(dashes == null) ? isbn
: dashes.collect { isbn.substring(*it) }.join('-')
}
Ranges make for a bit less clutter, IMO:
private isbnify3(String isbn) {
def dashesAt = [ 10: [0, 1..6, 7..8, 9],
13: [0..2, 3, 4..9, 10..11, 12]]
def dashes = dashesAt[isbn?.length()]
dashes == null ? isbn : dashes.collect { isbn[it] }.join("-")
}
With an inject-with-two-accumulators it should be easy to do a list-of-dash-positions version, too.
This should be a comment to #everton, but I don't have the 50 reputation needed to do that yet. So this answer is really just a suggested variation on #everton's answer.
One less regex by making the first 3 digits optional. The downside is having to remove a leading '-' if the ISBN is 10 characters. (I also prefer \d over \d{1}.)
private formatISBN(String isbn) {
String result = isbn.replaceAll(/^(\d{3})?(\d)(\d{6})(\d{2})(\d)$/,
'$1-$2-$3-$4-$5')
if (result) {
return result.startsWith('-') ? result[1..-1] : result
} else {
return isbn // return value unchanged, pattern didn't match
}
}
println formatISBN('1234567890')
println formatISBN('9991234567890')
println formatISBN('123456789') // test an ISBN that's too short
println formatISBN('12345678901234') // test an ISBN that's too long