Count value in template expression - templates

I want to count a value inside a template expression, in Xtend, without printing it out.
This is my code:
def generateTower(Tower in) {
var counter = 0.0;
'''
One Two Three Four
«FOR line : in.myTable»
«counter» «line.val1» «line.val2» «line.val3»
«counter = counter + 1»
«ENDFOR»
'''
}
So this will generate a table with four columns, whereas the first column is incremented starting at 0.0. The problem is, that «counter = counter + 1» is printed as well. But I want the expression above to just count up, without printing it out.
What could be the best solution to solve this problem?

You could use this simple and readable solution:
«FOR line : in.myTable»
«counter++» «line.val1» «line.val2» «line.val3»
«ENDFOR»
If you insist on the separate increment expression, use a block with null value. This works because the null value is converted to empty string in template expressions (of course you could use "" as well):
«FOR line : in.myTable»
«counter» «line.val1» «line.val2» «line.val3»
«{counter = counter + 1; null}»
«ENDFOR»
Although the first solution is the better. If you require complex logic in a template expression I recommend implementing it by methods not by inline code...
And finally, here is a more OO solution for the problem:
class TowerGenerator {
static val TAB = "\t"
def generateTower(Tower in) {
var counter = 0
'''
One«TAB»Two«TAB»Three«TAB»Four
«FOR line : in.myTable»
«generateLine(line, counter++)»
«ENDFOR»
'''
}
def private generateLine(Line line, int lineNumber) '''
«lineNumber»«TAB»«line.val1»«TAB»«line.val2»«TAB»«line.val3»
'''
}

Xtend is a full-fledged programming language. You can write Java-like expressions and templates. The problem there is that you're inside a triple quote (template), and everything you write there gets outputted. You can count inside the loop, but take into account that you're counting the elements in the in.myTable collection, and this can be obtained using in.myTable.length. So count could be calculated beforehand as in.myTable.length.

«{counter = counter + 1; null}» definitely worked. But as a recommendation, since it is java, writing it as «{counter++; null}» should do the trick as well. It helps because, you may need to modify your code and you can also put it in front as in: ++counter - by putting the operator first, the compiler takes a number, adds one to it before reading the value.

Related

problem in using list in game maker studio

I am new to the game maker. I created a list and I want to compare all the data in the list with a specific value. I used the following code:
for(var i=0;i<ds_list_size(lst);i++;)
{
if ds_list_find_value(lst,i)>tmp
ds_list_replace(lst,i,ds_list_find_value(lst,i)-1);
}
and I face the following error:
Push :: Execution Error - Variable Get -1.lst(100001, -1)
at
gml_Object_object0_RightButtonPressed_1 (line 21) - for(var i=0;i
where is my problem?
Thanks all.
if your first for loop i = 0; and when the first entry in the list is smaller than tmp it tries to replace the first place in the list with a not existing one. so you could either check if its the first entry of the list with
if ( i == 0 ) { }
or your could start the for loop from the second entry with
for(var i=1;i<ds_list_size(lst);i++;)
I think the ; at the end of i++; is unnecessary, you only need to use ; in a for-loop as seperator.
GML gives more freedom to common C# rules though (like how there are no brackets needed around an if-condition), so perhaps that's allowed.
Another possibility might be that the index is out of range at ds_list_replace()

How do I convert a Char to Int?

So I have a String of integers that looks like "82389235", but I wanted to iterate through it to add each number individually to a MutableList. However, when I go about it the way I think it would be handled:
var text = "82389235"
for (num in text) numbers.add(num.toInt())
This adds numbers completely unrelated to the string to the list. Yet, if I use println to output it to the console it iterates through the string perfectly fine.
How do I properly convert a Char to an Int?
That's because num is a Char, i.e. the resulting values are the ascii value of that char.
This will do the trick:
val txt = "82389235"
val numbers = txt.map { it.toString().toInt() }
The map could be further simplified:
map(Character::getNumericValue)
The variable num is of type Char. Calling toInt() on this returns its ASCII code, and that's what you're appending to the list.
If you want to append the numerical value, you can just subtract the ASCII code of 0 from each digit:
numbers.add(num.toInt() - '0'.toInt())
Which is a bit nicer like this:
val zeroAscii = '0'.toInt()
for(num in text) {
numbers.add(num.toInt() - zeroAscii)
}
This works with a map operation too, so that you don't have to create a MutableList at all:
val zeroAscii = '0'.toInt()
val numbers = text.map { it.toInt() - zeroAscii }
Alternatively, you could convert each character individually to a String, since String.toInt() actually parses the number - this seems a bit wasteful in terms of the objects created though:
numbers.add(num.toString().toInt())
On JVM there is efficient java.lang.Character.getNumericValue() available:
val numbers: List<Int> = "82389235".map(Character::getNumericValue)
Since Kotlin 1.5, there's a built-in function Char.digitToInt(): Int:
println('5'.digitToInt()) // 5 (int)
https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.text/digit-to-int.html
For clarity, the zeroAscii answer can be simplified to
val numbers = txt.map { it - '0' }
as Char - Char -> Int. If you are looking to minimize the number of characters typed, that is the shortest answer I know. The
val numbers = txt.map(Character::getNumericValue)
may be the clearest answer, though, as it does not require the reader to know anything about the low-level details of ASCII codes. The toString().toInt() option requires the least knowledge of ASCII or Kotlin but is a bit weird and may be most puzzling to the readers of your code (though it was the thing I used to solve a bug before investigating if there really wasn't a better way!)

for loop stops when if statement is satisfied

I am trying to count how many times the unique words in a LinkedList appear using this code:
for(int i2 = 0; i2 < a.size(); i2++)
{
word2 = a.get(i2);
for(int j2 = 0; j2 < a.size(); j2++)
{
if(word2 == a.get(j2))
{
counter++;
}
}
System.out.println(word2 + " : " + counter);
counter = 0;
}
But the counter prints out:
Alphabet : 1
Alright : 1
Apple : 1
Alphabet : 1
Alright : 1
Apple : 1
Alphabet : 1
Alright : 1
Apple : 1
There is obviously more than one of the words, but the counter never gets higher then one. I think that the inner for loop is stopping when the if statement is satisfied, but I don't want it to. Any suggestions?
You should use
word2.equals(a.get(j2))
Using "==" you compare the references to those String which are not equal.
And by the way you will print the counter multiple times for the same word if you have repetitions. Let's say you have the word Apple on 2 positions in your list. When you will reach these 2 positions the counter will go up to 2 and you will print (Apple: 2) 2 times
This seems like java to me. You can't compare string with (==) operator.
if(word2.equals(a.get(j2)))
Just a new addition!!!
As suggested by #user3412998 its better to use Sets so that you can avoid duplication.
Now if you need to use ArrayList only then you need to take one element and check if there are multiple copies of that element using loop.The condition can be checked by .equals method if you are using string or my contains method incase you are inserting objects(dont forget to override your equals method in the corresponding class). This is a very tedious process and I do not recommend it.
I believe that the easiest way will to not to add duplicate elements in your array list. to accomplish that look at the code below..
if(!a.contains(word)){
a.add(word);
}
Note word is a String object.
Here I am checking weather the string is already contained in the ArrayList, before insertion.
make a bit of modifications so that you can use it, for arrays, or for directly inputting data etc..
I hope this helps..

Count number of occurrences based on 2 conditions or Regexp

How can I get the number of occurrences for some range based on
A regular expression
2+ conditions; let's say cells that contain "yes" and / or "no"
What I've got for the moment:
COUNTIF(B5:O5; "*yes*")
I tried to use COUNTIF(B5:O5; {"*yes*", "*no*"}) or COUNTIF(B5:O5; "(*yes*)|(*no*)"), but neither of them worked.
Or, how do I count cells that contain some domain names—yahoo.com, hotmail.com, and gmail.com—using regexp? e.g.:
(\W|^)[\w.+\-]{0,25}#(yahoo|hotmail|gmail)\.com(\W|$)
The most pedestrian solution to your problem (tested in Excel and Google Docs) is to simply add the result of several countif formulas:
=COUNTIF(B5:O5, "*yes*") + COUNTIF(B5:O5, "*no*")
This expression will count the total of cells with "yes" or "no". It will double count a cell with "yesno" or "noyes" since it matches both expressions. You could try to take out the doubles with
=COUNTIF(B5:O5, "*yes*") + COUNTIF(B5:O5, "*no*") - COUNTIF(B5:O5, "*no*yes*") - COUNTIF(B5:O5, "*yes*no*")
But that will still get you in trouble with a string like noyesno.
However there is a rather clever trick in Google Docs that may just be a hint of the solution you are looking for:
=COUNTA(QUERY(A1:A9, "select A where A matches '(.*yes.*)|(.*no.*)'"))
The QUERY function is like a mini database thing. In this case it looks at the table in range A1:A9, and selects only elements in column A where the corresponding element in column A matches (in the preg regex sense of the word) the expression that follows - in this case, "anything followed by yes followed by anything, or anything followed by no followed by anything". In a simple example I made, this counts a yesnoyes only once - making it exactly what you were asking for (I think...)
Right now your range B5:O5 is several columns wide, and only one row high; that makes it hard to use the QUERY trick. Something rather less elegant (but that works regardless of the shape of the range) is this:
=countif(arrayformula(isnumber(find("yes",A1:A9))+isnumber(find("no",A1:A9))),">0")
The sum of the isnumber functions acts as an element-wise OR - unfortunately, the regular OR function doesn't seem to work on individual elements of an array. As before, this finds cells that contain either "yes" or "no", and counts the ones that have either of these strings contained within.
This is heavily inspired by Floris's answer. See the comments, in particular. If you TRANSPOSE the row of items to compare against, QUERY works fine for horizontal data as well:
=COUNTA(QUERY(TRANSPOSE(B5:O5), "select * where Col1 matches '.*(yes|no).*'"))
As far as I can tell, Col1 is "special" and case sensitive!
Recently I wanted this functionality in a Google Sheet. I came up with a different solution that also looks very readable.
=COUNTIF(ARRAYFORMULA(REGEXMATCH(O36:R36,"(yes|no)")),TRUE)
Basically what it does is, run REGEXMATCH over a range using ArrayFormula which returns either TRUE or FALSE. And then use COUNTIF to count the occurances of TRUE.
The easiest way NGix found is to create a custom function for these purposes. They added 2 that work perfectly for them and hope it'll help someone too:
/**
* Count if cell value matches any condition ( supports regexp also )
*/
function countCustomMatchOr(data){
var count = 0;
for(var i=0; i < data.length; i++){
for(var j=0; j<data[i].length; j++){
var cell = data[i][j];
for(var k=1;k<arguments.length;k++){
if(typeof arguments[k] == "number"){
if(arguments[k] == cell) count++;
} else if(cell.toString().match(arguments[k])) count++;
}
}
}
return count;
}
And
/**
* Counts value in data range if matches regular expression
*/
function countCustomRegExp(data, reg, flag){
var rows = data.length, count = 0, re = flag?new RegExp(reg, flag):new RegExp(reg);
for( var i = 0; i < rows; i++){
for( var j = 0; j < data[i].length; j++){
if( data[i][j] != "" && data[i][j].toString().match(re) ){
count++;
}
}
}
return count;
}
In order to use them just apply countCustomRegExp(A2:G3;"yes.*") or countCustomMatchOr(A2:G3;"yes";"no")
I've had the same problem, if you don't want to use VBA, try to add a SUM to your formula:
=SUM(COUNTIF(B5:O5; {"*yes*", "*no*"}))

Limit size of a list in python

I want to limit the size of a list in python 2.7 I have been trying to do it with a while loop but it doesn't work
l=[]
i=raw_input()//this is the size of the list
count=0
while count<i:
l.append(raw_input())
count=count+1
The thing is that it does not finish the loop. I think this problem has an easy answer but I can't find it.
Thanks in advance
I think the problem is here:
i=raw_input()//this is the size of the list
raw_input() returns a string, not an integer, so comparisons between i and count don't make sense. [In Python 3, you'd get the error message TypeError: unorderable types: int() < str(), which would have made things clear.] If you convert i to an int, though:
i = int(raw_input())
it should do what you expect. (We'll ignore error handling etc. and possibly converting what you're adding to l if you need to.)
Note though that it would be more Pythonic to write something like
for term_i in range(num_terms):
s = raw_input()
l.append(s)
Most of the time you shouldn't need to manually keep track of indices by "+1", so if you find yourself doing it there's probably a better way.
That is because i has a string value type, and int < "string" always returns true.
What you want is:
l=[]
i=raw_input() #this is the size of the list
count=0
while count<int(i): #Cast to int
l.append(raw_input())
count=count+1
You should try changing your code to this:
l = []
i = input() //this is the size of the list
count = 0
while count < i:
l.append(raw_input())
count+=1
raw_input() returns a string while input() returns an integer. Also count+=1 is better programming practice than count = count + 1. Good luck