I am trying to add only certain rows to this output. Currently this output adds all rows, which is used for a Total row at the very end of
<cfoutput query="qrySummary">
#numberFormat(ArraySum(ListToArray(ValueList(qrySummary.secThreeCount))), ",")#
This obviously totals all of SecThreeCount values, but what if I want to exclude the last 2 rows from that list??
Is that possible in coldfusion?
(If this makes a difference)>> So there are 13 rows returning, I want the first 11 rows and exclude the last 2.
I know that I can limit the SQL return of that query to exclude those 2 rows, but I wanted less code to write and keep things neat. And also learn if it is possible:)
Thanks in advance.
Well I think if you don't need those two rows, you should not be returning them in the first place. That would be the best answer. From your statement "but I wanted less code to write" you're optimising in the wrong place: don't optimise for yourself, optimise for the solution.
Leigh's come in underneath me as I've been testing the code for this, but here's a proof of concept using subList():
numbers = queryNew("");
queryAddColumn(numbers, "id", "integer", [1,2,3,4,5,6]);
queryAddColumn(numbers, "maori", "varchar", ["tahi", "rua", "toru", "wha", "rima", "ono"]);
maori = listToArray(valueList(numbers.maori));
subset = maori.subList(2,5);
writeDump([numbers, subset]);
This returns an array with elements ["toru","wha","rima"].
If you are running CF10, one option is using ArraySlice. Grab only the first eleven elements, then apply arraySum.
<cfset allValues = ListToArray(ValueList(qrySummary.secThreeCount))>
<cfset subTotal = arraySum( arraySlice(allValues, 1, 11))>
For earlier versions, there is the undocumented subList(...) approach. It takes advantage of the fact that CF arrays are java.util.List objects under the hood, and uses List.subList(..) to grab a subset of the array.
Another approach. You don't want to add up the values for the last 2 elements, so remove them from your array:
<cfset values = ListToArray(ValueList(qrySummary.secThreeCount))>
<!--- delete the last element --->
<cfset arrayDeleteAt(values, arrayLen(values))>
<!--- delete the last element again --->
<cfset arrayDeleteAt(values, arrayLen(values))>
#numberFormat(ArraySum(values), ",")#
Alternatively, given that you're looping over the query anyway, you could simply add the totals up as you go (with a tiny bit of logic to not bother if you're on the last or penultimate row)
Related
This may be something really simple, but I couldn't figure it out and been trying to find an example online to no avail. I'm basically trying to remove items found in one sequence from another sequence.
Example #1
Items added to the cart is in one sequence; items removed from cart is in another sequence:
<#assign Added_Items_to_Cart = "AAAA,BBBB,CCCC,DDDD,EEEE,FFFF">
<#assign Deleted_Items_from_Cart = "BBBB,DDDD">
The result I'm looking for is: AAAA,CCCC,EEEE,FFFF
Example #2
What if the all items added to and deleted from cart are in the same sequence?
<#assign Cart_Activity = "AAAA,BBBB,BBBB,CCCC,DDDD,EEEE,DDDD,FFFF,Add,Add,Delete,Add,Add,Add,Delete,Add">
The result I'm looking for is the same: AAAA,CCCC,EEEE,FFFF
First things first: You ask about sequence but the data you are dealing with are strings.
I know you are using the string to work as a sequence (and it works), but sequences are sequences and strings are strings, and they have diferente ways of dealing with. I just felt this was important to clarify if someone who is starting to learn how to program get to this answer.
Some assumptions since you're providing strings with data separated by comma:
You want a string with data separated by comma as a result.
You know how to properly create strings with data separated by comma.
You dont have commas in your items names.
Observations:
I'll give you the logic but not the code donne, as this can be a great chance for you to learn/practice freemarker (stackoverflow spirit, you know...)
You question is not about something specific of freemaker (it just happens to be the language you want to work with). Think about adding the logic tag to you question. :-)
Now to the answer on how to do what you want on a "string that is working as a sequence":
Example #1
Change your string to a real sequence :-)
1 - Use a built-in to split your string on commas. Do it for both Added_Items_to_Cart and Deleted_Items_from_Cart. Now you have two real sequences to work with.
2 - Create a new string tha twill be your result .
3 - Iterate over the sequence of added itens.
4 - For each item of the added list, you will check if the deleted list also contains this item.
4.1 - If the deleted list contains the item you do nothing.
4.2 - If the deleted list do not contains the item, you add that item to your string result
At the end of this nested iteration (thats another hint) you should get the result you're looking for.
Example #2
There are many ways of doing it and i'll just share the one that pops out of my mind right now.
I think it's noteworthy that in this approach you will always have an even sized list, as you always insert 2 infos each time: item and action.
So always the first half will be the 'item list' and the second half will be the 'action list'.
1 - Change that string to a sequence (yes, like on the other example).
2 - Get half of its size (in your example size = 16 so half of it is 8)
3 - Iterate over a range from 0 to half-1 (in your example 0 to 7)
4 - At each iteration you'll have a number. Lets call it num (yes I'm very creative):
4.1 - If at the position num + half you have the word "Add" you add the item of position num in your result string
4.2 - If at the position num + half you have the word "Delete" you remove the item of position num from your result string
And for the grand finale, some really usefull links that will help you in your freemarker life forever!!!
All built-ins from freemarker:
https://freemarker.apache.org/docs/ref_builtins.html
All directives from freemarker:
https://freemarker.apache.org/docs/ref_directive_alphaidx.html
Freemarekr cheatsheet :
https://freemarker.apache.org/docs/dgui_template_exp.html#exp_cheatsheet
I would like to split my Variables "Wellbeing_Pre" and "Wellbeing_Post" to one Wellbeing variable and one Pre/Post-Variable, so that I have one row for each pre and post and one column for the variable "wellbeing" and one for the variable "Pre / Post" (0=pre, 1=post).
I have already a long-format in my data where there are several rows for each person for every measurment point. Now I would like to split the Pre Post Measurments to separate rows as well.
I'm grateful for ideas! :-)
To elaborate #horace_vr's solution:
varstocases make Wellbeing from Wellbeing_Pre Wellbeing_Post /index=PPtxt(Wellbeing).
* variable PPtxt now has the values "Wellbeing_Pre" and "Wellbeing_Post".
* If you want a numeric 1/0 variable instead, do the following.
recode PPtxt ("Wellbeing_Pre"=0) ("Wellbeing_Post"=1) into Pre_Post.
exe.
The list starts empty. Then I want to append an value to it for each iteration in a loop if certain condition is met. I don't see append option in Variable Operation.
You can use string split for this, assuming you know of a delimiter that won't ever be in your list of values. I've used a semi-colon, and $local_joinedList$ starts off empty.
If (certain condition is met)
Variable Operation: $local_joinedList$;$local_newValue$ To $local_joinedList$
End If
String Operation: Split "$local_joinedList$" with delimiter ";" and assign output to $my-list-variable$
This overwrites $my-list-variable$.
If you need to append to an existing list, you can do it the same way by using String Join first, append your values to the string, then split it again afterward.
String Operation: Join elements of "$my-list-variable$" by delimiter ";" and assign output to $local_joinedList$
Lists are buggy in Automation Anywhere and have been buggy for several versions. I suggest not using them and instead use XML.
It it a much more versatile approach and allows you to do much more that with lists. You can search, filter, insert, delete etc.
For the example you mention, you would use the "Insert Node" command.
Throwing in my 2 cents as well - my-list-variable appears to be the only mutable in size list you can work with. From my experience with 10.7, it only grows though.
So if you made a list with 60 values, and you wanted to use my-list-variable again for 55, you'll need to clear out those remaining 5 values and create an if condition when looping over the list to ensure the values are not whatever you set those 5 values to be.
I used lime's answer as a reference (thanks lime!) to populate a list variable from some data in an Excel spreadsheet.
Here's my automation for it:
This works:
connection = get_connection()
cursor=connection.cursor()
cursor.execute('show application_name')
application_name_of_connection=cursor.fetchone()[0]
But why four lines? Is there no way to get this in one line?
No, there is not a way to do this in one line. Languages such as Python are designed to describe a set of instructions. There are four instructions here. There may even be helper methods or clever/inefficient arrangements of these statements that could lower this to three lines, but you are best to keep it how it is.
For example, if you are for some reason using this code frequently, you would encapsulate it in its own method
def get_application_name_of_connection()
connection = get_connection()
cursor=connection.cursor()
cursor.execute('show application_name')
return cursor.fetchone()[0]
And then simply:
get_application_name_of_connection()
This is how it works. You want less code? Hide the functionality.
It can be done with comprehension but on sqlite:
results = [row[0] for row in get_connection().cursor().execute('select * from mytable')]
If you are using postgresql then it doesn't work, you could try this for a more compact form:
with get_connection().cursor() as cur:
cur.execute('show all')
print cur.fetchone()
But only if you need the cursor thrown away after the block execution.
I didn't tried on other db managers, results may vary.
Not sure if this is possible or not. What I am trying to do is build an output string via queries. I am concatenating the output "name" and appending the "value" to the end. Then outputting the string. I don't think this is possible. But I am looking for any alternatives.
So this is what I have:
qry1 is the main query. qry2 gets the value to append to the end of the string.
So the value of variable test would look like this: "variables.qry1.100"
Which would make sense to qry1 as this is part of the query object. So then this string would return a correct value from the database as there is a subquery called 100
<cfoutput>
<cfloop query="variables.qry2">
<cfset test = variables.qry1. & variables.qry2.#valueID#>
<td>#test#</td>
</cfloop>
</cfoutput>
Many thanks.
JC
So basically - given your example - you have a column in qry1 called 100 (etc, perhaps also 200, 300 etc), and the values 100, 200, 300 etc are row values in the valueID column of qry2? And qry1 is a single-row query? Is that right?
If you have the name of the column in a dynamic string, you use this syntax:
queryName[columnName][rowNumber]
Where queryName is the variable that is the query, columnName is the string holding the column name, and rowNumber is the row number (either an actual number, or a variable containing one).
So using your example variables, you code would be:
<td>#variables.qry1[variables.qry2.valueID][1]#</td>
There is no need to use evaluate() to do this, and it is not a good solution here. There is very seldom a need to use evaluate() in CFML, since the days of CF5.
I have no idea of the background of how your data structures came to be the way they are, but if you are needing to write the sort of code you are suggesting you need to... I'd be looking long and hard at how you're going about things.
What your trying to do is possible, but you need to build a variable name first.
Instead of
<cfset test = variables.qry1. & variables.qry2.#valueID#>
Try
<cfset test = "variables.qry1.#variables.qry2.valueID#">
Test will then be variables.qry1.[valueID value]. Note that [valueID value] is what is getting returned from the query, so the actual value inside the variable.
Then to display the value of variables.qry1.[valueID value].
#evaluate(test)#
UPDATE As stated by Adam Cameron's answer. You should really try to avoid the evaluate() function, it's quite a performance hit and not considered good practice. Instead rather use the following code (This is copied from Adam Cameron's answer)
#variables.qry1[variables.qry2.valueID][1]#
NOTE: Go look at Adam Cameron's answer for a better description of whats going on.
Adam has the correct solution. Here is a modified version of your original code that does what I think you are trying to do.
<cfoutput query="variables.qry1">
<tr>
<cfloop query="variables.qry2">
<cfset test = variables.qry1[variables.qry2.valueID][variables.qry1.currentrow]>
<td>#test#</td>
</cfloop>
</tr>
</cfoutput>