I need to display the first item that fulfills some condition. Something I would normally do via construction like this pseudocode:
for(item in some_array)
if(some_condition(item)) {
some_action();
break;
}
The problem is I need to do that in TWIG and TWIG does not allow to break a for loop. How to do that then?
You could use a boolean to denote that you have processed the first item but it will continue to loop over the rest of the array:
set firstItemProcessed = false;
for(item in some_array) {
if(firstItemProcessed == false and some_condition(item) ) {
some_action();
firstItemProcessed = true;
}
}
Related
I have the following piece of code:
sql.eachRow(query){
def i=1
println("$i --> $it.columnName")
i++
}
If query returns some records(rows), there is no problem.
But if query is returning 0 records then how should I handle it. I want to show a user-friendly message, such as ZERO RECORDS FOUND.
def i=0
sql.eachRow(query) {
i++
println(i+" --> "+ it.columnName)
}
if (i == 0) {
println "ZERO RECORDS FOUND"
}
def rows = sql.rows(query)
if (rows.empty) {
// logic for handling no rows
} else if (rows.any { it.name == 'something' }) {
// logic for handling isExists == true
} else {
// logic for handling isExists == false
}
I'm not sure what's your specific case is, but it may be a case that checking name == 'something' condition can be done straight away at SQL level with WHERE name = 'something'. Then you could get rid off one of logical blocks in if statement.
It's not critical but I was wondering. Somewhere in my program I have a switch statement that gets called multiple times with an incremented value, so that all cases should be executed in order. Something like a custom made simple sequencer.
like this:
private function sequence_Crush(step:Int):Void
{
switch(step) {
case 1: {
action_loadCueFile();
seq.next(); //This calls the same function with an increased step
}
case 2: {
action_saveSettings();
seq.next();
}
/// EDIT: Some steps run ASYNC and an event triggers the next step in the sequence
/// like this:
case 3: {
events.once(ENGINE_EVENTS.cut_all_complete, seq.next);
cutTracks();
}
My Question is, Is there any way to replace the manually written numbers (1,2,3,4) on the cases and use a counter somehow, macros maybe? I have tried putting a dynamic counter, but the Haxe compiler complains.
What I tried:
var st:Int = 1;
switch(step) {
case (st++): { // 1
action_loadCueFile();
seq.next();
}
case (st++): { // 2
action_saveSettings();
seq.next();
}
//... etc
Build halted with errors (haxe.exe)
Case expression must be a constant value or a pattern, not an arbitrary expression
I am targeting JS and using Haxe 3.1.3. I have tried that in actionscript and javascript and it works fine. The reason I want to do that, is that if I want do add or remove a step, I have to re-organize manually every other case number.
p.s. I know there are other ways to sequence actions in order, but I like this one, as I have everything in one function and it's easy to see the order of execution in one glance
Thanks for reading :-)
Jason beat me to it by a few minutes...
Case expressions in Haxe must be either constant values or patterns.
But you can accomplish the desired behaviour in a few ways: (a) custom syntax like $next with macros; (b) macro conversion into if-else blocks (Jason's answer); (c) without macros and (mis)using pattern guards.
Custom syntax
A quick and dirty implementation of it follows; it only supports case $next: and there are no syntax checks.
When a case $next: is found, the macro checks if the previous case pattern was a single constant integer i and, in that case, rewrites the pattern to the value of i + 1.
Macro implementation:
// SequenceSwitch.hx
import haxe.macro.Context;
import haxe.macro.Expr;
import haxe.macro.ExprTools;
class SequenceSwitch {
public
macro static function build():Array<Field> {
var fields = Context.getBuildFields();
for (f in fields)
switch (f.kind) {
case FFun(func) if (func.expr != null):
func.expr = ExprTools.map(func.expr, transf);
case _:
}
return fields;
}
static function transf(e:Expr):Expr {
return switch (e.expr) {
case ESwitch(expr, cases, def):
var ncases = [];
var prev:Array<Expr> = null;
for (c in cases) {
var cur = switch (c.values) {
case [{ expr : EConst(CIdent("$next")), pos : pos }] if (prev != null):
switch (prev) {
case [{ expr : EConst(CInt(i)) }]:
var next = { expr : EConst(CInt(Std.string(Std.parseInt(i) + 1))), pos : pos };
{ values : [next], guard : c.guard, expr : c.expr };
case _:
c;
}
case _:
c;
};
ncases.push(cur);
prev = cur.values;
}
{ expr : ESwitch(expr, ncases, def), pos : e.pos };
case _:
e;
}
}
}
Usage example:
// Text.hx
#:build(SequenceSwitch.build())
class Test {
static function main() {
sequenceCrush(1);
}
static function sequenceCrush(step:Int) {
switch (step) {
case 1:
trace("do one");
sequenceCrush(++step);
case $next:
trace("do two");
sequenceCrush(++step);
case $next:
trace("do three");
sequenceCrush(++step);
case _:
trace("terminate");
}
}
}
No macros/with guards
Similar behaviour could be achieved by (mis)using guards:
static function sequenceCrush_guards(step:Int) {
var st = 1;
switch (step) {
case next if (next == st++):
trace("do one");
sequenceCrush_guards(++step);
case next if (next == st++):
trace("do two");
sequenceCrush_guards(++step);
case next if (next == st++):
trace("do three");
sequenceCrush_guards(++step);
case _:
trace("terminate");
}
}
In Haxe 3 switch changed from the JS/Flash style simple matching, which was really not much more than a chain of if/elseif/else statements, to full on pattern matching, which has many more compile-time features, and one of those limitations is that you can't match against a variable, only against constants.
You could use a chain of if (step==st++) {} elseif (step==st++) {} else {} statements for pretty much the same effect. If you're really really addicted to the switch syntax, you could use a macro to get the "classic" switch behaviour. I happened to write one such macro some time ago, take a look at this GIST:
https://gist.githubusercontent.com/jasononeil/5429516/raw/ad1085082530760aa394765d5cd5ebd61a5dbecb/ClassicSwitch.hx
You could then code like this:
class Action
{
static function main()
{
for (currentStep in 0...5) {
var i = 0;
ClassicSwitch.from(switch (currentStep) {
case i++: trace( 'Do step $i' );
case i++: trace( 'Do step $i' );
case i++: trace( 'Do step $i' );
case i++: trace( 'Do step $i' );
case i++: trace( 'Do step $i' );
});
}
}
}
Which gives me the output:
Action.hx:14: Do step 1
Action.hx:15: Do step 2
Action.hx:16: Do step 3
Action.hx:17: Do step 4
Action.hx:18: Do step 5
If all (or most) of your actions are simple function calls you can alternatively use an array of functions:
var actions = [sequence_Crush.bind(1), // if you want to avoid action index = step - 1
action_loadCueFile,
action_saveSettings,
...];
private function sequence_Crush(step:Int):Void
{
while (step < actions.length)
{
actions[step++]();
}
}
You could also keep this recursive (actions[step++](); if (step < actions.length) { sequence_Crush(step)).
I made a program that takes a text file, stores the lines as strings in an array. Now I want to "filter" those entries of the array.
I am using the string.contains to see if each array entry has the substring "05/Aug".
For some reason, it is always returning true, when in fact, it should not.
Here is the file: http://www.santarosa.edu/~lmeade/weblog.txt
And here is my code:
for (int i=0; i<10;i++)
{
boolean check = storestrings[i].contains("05/Aug");
if(check = true){
teststring[i] = storestrings[i];
//System.out.print(storestrings[i]);
}
else{
teststring[i] = null;
}
}
You used assignment operator in the if statement instead of equality. It should be like this:
if(check == true){
teststring[i] = storestrings[i];
//System.out.print(storestrings[i]);
}
or simply
if (check) {
teststring[i] = storestrings[i];
//System.out.print(storestrings[i]);
}
In your code, when it reached check = true in the if statement, it assigns true to the check variable and returns true so the if condition always evaluates to true.
What is the Groovy equivalent to the forAll method in OCL?
Let's say that I have a list of items.
def items = new LinkedList<Item>();
What is the Groovy way to express a predicate that holds if and only if all items match a certain criteria?
The following code snippet does not work, because the inner return only jumps out of the current iteration of the each closure, not out of the forAll method.
boolean forAll(def items)
{
items.each { item -> if (!item.matchesCriteria()) return false; };
return true;
}
The following code snippet, which should do the trick, feels cumbersome and not Groovy-like.
boolean forAll(def items)
{
boolean acceptable = true;
items.each { item -> if (!item.matchesCriteria()) acceptable = false; };
return acceptable;
}
I am looking for a way to lazily evaluate the predicate, so that the evaluation would finish when a first non-matching item is found.
You can use every
items.every { it.matchesCriteria() }
In groovy that's very easy:
def yourCollection = [0,1,"", "sunshine", true,false]
assert yourCollection.any() // If any element is true
or if you want to make sure, all are true
assert !yourCollection.every()
you can even do it with a closure
assert yourCollection.any { it == "sunshine" } // matches one element, and returns true
or
assert !yourCollection.every { it == "sunshine" } // does not match all elements
I wanted to call my custom method in the Thread.
public void LoopOverAllLists(String _webAndSiteXml)
{
try
{
XmlNode _nodelist = SharePoint.ListsGetListCollection();
foreach (System.Xml.XmlNode _item in _nodelist.ChildNodes)
{
string title = _item.Attributes["Title"].Value;
//check for hidden list
if (_item.Attributes["Hidden"].Value.ToLower() == "false")
{
switch (_item.Attributes["ServerTemplate"].Value)
{
//Check whether list is document library
case SharePoint.LIST_ID_DOCUMENT_LIBRARY:
case SharePoint.LIST_ID_XML_FORMS:
case SharePoint.Publishing_ID_Pages:
{
//Get all documents info
try
{
GetAllDocumentsInfo(_item, _webAndSiteXml);
}
catch
{
}
break;
}
//Check whether list is having attachment
case SharePoint.LIST_ID_GENERIC:
case SharePoint.LIST_ID_ANNOUNCEMENTS:
case SharePoint.LIST_ID_CONTACTS:
case SharePoint.LIST_ID_TASKS:
case SharePoint.LIST_ID_EVENTS:
case SharePoint.LIST_ID_CUSTOM_GRID:
case SharePoint.LIST_ID_MEETING_SERIES:
case SharePoint.LIST_ID_MEETING_AGENDA:
case SharePoint.LIST_ID_MEETING_ATTENDEES:
case SharePoint.LIST_ID_MEETING_DECISIONS:
case SharePoint.LIST_ID_MEETING_OBJECTIVES:
case SharePoint.LIST_ID_MEETING_TTB:
case SharePoint.LIST_ID_MEETING_WS_PAGES:
case SharePoint.LIST_ID_PORTAL_SITE_LIST:
{
//Get all list items info having attachment
try
{
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
}
catch
{
}
break;
}
default:
GetAllListItemsInfoOnlyAttachments(_item, _webAndSiteXml);
break;
}
// Get All the List Forms
try
{
GetAllListForms(title, _webAndSiteXml);
}
catch
{
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
in above method three methods which is " GetAllDocumentsInfo , GetAllListItemsInfoOnlyAttachments and GetAllListForms " I wanted to call these function using thread in C#.
Thanks
Here is how I would approach the problem. Notice that I encapsulated the contents of the foreach loop into a separate method and then queued the execution of that method into the ThreadPool so that each iteration of the loop occurs in parallel. I also use a well established pattern to wait for all pending work items to complete. This code is compatible with .NET 3.5.
public void LoopOverAllLists(String _webAndSiteXml)
{
int pending = 1; // Used to track the number of pending work items.
var finished = new ManualResetEvent(false); // Used to wait for all work items to complete.
XmlNode nodes = SharePoint.ListsGetListCollection();
foreach (XmlNode item in nodes)
{
XmlNode capture = item; // This is required to capture the loop variable correctly.
Interlocked.Increment(ref pending); // There is another work item in progress.
ThreadPool.QueueUserWorkItem(
(state) =>
{
try
{
ProcessNode(capture);
}
finally
{
// Signal the event if this is the last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
}
}, null);
}
// Signal the event if the for loop was last work item to complete.
if (Interlocked.Decrement(ref pending) == 0) finished.Set();
// Wait for all work items to complete.
finished.WaitOne();
}
private void ProcessNode(XmlNode item)
{
// Put the contents of your loop here.
}
instead of calling
GetAllDocumentsInfo(_item, _webAndSiteXml);
use
Task.Factory.StartNew(() => GetAllDocumentsInfo(_item, _webAndSiteXml));
repeat this pattern for the other method calls as well