Discussion:
ColdFusion Structure
(too old to reply)
alecken
2009-02-13 17:30:14 UTC
Permalink
I'm looping an array of records (from a fixed length feed) and creating a
structure for each required field. Then for every loop, I'm passing this
structure to a function to check if certain required field in the structure's
element is left empty.
The structure should look something like this:
<cfloop from="1" to="#ArrayLen(MyFile)#" index="i">
<cfset aEachLine[i]=StructNew()>
<cfset aEachLine[i]["LastName"]="#Mid(MyFile[i],17,40)#">
<cfset aEachLine[i]["FirstName"]="#Mid(MyFile[i],57,20)#">
<cfset aEachLine[i]["Address"]="#Mid(MyFile[i],140,38)#">
<cfset aEachLine[i]["City"]="#Mid(MyFile[i],254,19)#">
<cfset aEachLine[i]["State"]="#Mid(MyFile[i],273,2)#">
<cfset aEachLine[i]["Country"]="#Mid(MyFile[i],284,4)#">

In this example I'm assuming that my structure is this short

<CFSET CheckStructValue=CheckThisStruc(aEachLine)>
</cfloop>

How do I check if any of those struct. value is empty?
BKBK
2009-02-13 17:42:38 UTC
Permalink
[i]How do I check if any of those struct. value is empty? [/i]

http://livedocs.adobe.com/coldfusion/8/htmldocs/help.html?content=functions_s_18
.html gives the number of keys in myStructure. It will return 0 if myStructure
has no keys.
alecken
2009-02-13 18:06:22 UTC
Permalink
StructCount(myStrcuture) doesn't check for an empty value isn't it?
If in that structure, key Country does have value or the value is emty string
how can I catch that, I thnk that is what I'm after.

As far as the logic, I'm looping from a fixed length text file. First I
created an Array using the <cfset MyFile =
listtoarray(MyFile,"#chr(13)##chr(10)#")>
This give me and array of fixed length records, then I loop over this array
creating a structure for each required record and then checking each element of
the structure if they are empty. The difficulty I'm facing is how to check
the value of the structure element on every loop.
craigkaminsky
2009-02-13 18:27:42 UTC
Permalink
To simply check the value of each key in a struct, use a collection loop.

The syntax is:
<cfloop collection="#myStruct#" item="key">
<cfif Trim(myStruct[key)] eq "">
<!--- do what you gotta here, because the key is empty --->
</cfif>
</cfloop>

You can also get the name of the key in the above loop by outputting or
checking the value of the item (key).
<cfoutput>#key#</cfoutput>
Or
<cfif key eq "country">
<!--- blah blah --->
</cfif>
CF-Pensioner
2009-02-14 12:28:29 UTC
Permalink
In your code here you are creating a new structure every itieration.

[q][i]
<cfloop from="1" to="#ArrayLen(MyFile)#" index="i">
<cfset aEachLine[I]=StructNew()>
<cfset aEachLine[I]["LastName"]="#Mid(MyFile[I],17,40)#">
<cfset aEachLine[I]["FirstName"]="#Mid(MyFile[I],57,20)#">
<cfset aEachLine[I]["Address"]="#Mid(MyFile[I],140,38)#">
<cfset aEachLine[I]["City"]="#Mid(MyFile[I],254,19)#">
<cfset aEachLine[I]["State"]="#Mid(MyFile[I],273,2)#">
<cfset aEachLine[I]["Country"]="#Mid(MyFile[I],284,4)#">

In this example I'm assuming that my structure is this short

<CFSET CheckStructValue=CheckThisStruc(aEachLine)>
</cfloop>
[/q]

BKBK is saying this is inefficient. It is because for each new structure,
coldfusion is using memory and processing power. Rather do this.




<cfset myTmpStruct = StructNew()>

<cfloop from="1" to="#ArrayLen(MyFile)#" index="i">
<cfset myTmpStruct ["LastName"]="#Mid(MyFile,17,40)#">
<cfset myTmpStruct ["FirstName"]="#Mid(MyFile,57,20)#">
<cfset myTmpStruct ["Address"]="#Mid(MyFile,140,38)#">
<cfset myTmpStruct ["City"]="#Mid(MyFile,254,19)#">
<cfset myTmpStruct ["State"]="#Mid(MyFile,273,2)#">
<cfset myTmpStruct ["Country"]="#Mid(MyFile,284,4)#">

In this example I'm assuming that my structure is this short

<CFSET CheckStructValue=CheckThisStruc(aEachLine)>
</cfloop>
CF-Pensioner
2009-02-14 12:37:36 UTC
Permalink
Is this code even working? You use the Mid() function on an array in each
iteration of the loop. Did you just post code that is incomplete?

For example where you have


<cfset aEachLine["LastName"]="#Mid(MyFile,17,40)#">
<!--- it should be --->
<cfset aEachLine["LastName"]="#Mid(MyFile[i],17,40)#">
BKBK
2009-02-14 17:34:12 UTC
Permalink
Alecken wrote:
[i]As far as the logic, I'm looping from a fixed length text file. First I
created an Array using the <cfset MyFile =
listtoarray(MyFile,"#chr(13)##chr(10)#")>
This give me and array of fixed length records, then I loop over this array
creating a structure for each required record and then checking each element of
the structure if they are empty. [/i]

OK. I think there is a misunderstanding. It has to with the fact that this
forum uses [ i ] for italics. The indices i that you used in MyFile[ i ] have
therefore disappeared from the right-hand side of the statements, leaving only
MyFile in each case.

However, the point about moving <cfset aEachLine =StructNew()> outside the
loop stays. Otherwise, you will be creating a new object with each pass of the
loop, for nothing.

An alternative is to leave the line where it is. But then, modify it by giving
the struct an extra key (the index). That's what I've done below.




<cfloop from="1" to="#ArrayLen(MyFile)#" index="j">
<cfset aEachLine["#j#"] =StructNew()>
<cfset aEachLine["#j#"]["LastName"]=trim(Mid(MyFile[j],17,40))">
<cfset aEachLine["#j#"]["FirstName"]=trim(Mid(MyFile[j],57,20))">
<cfset aEachLine["#j#"]["Address"]=trim(Mid(MyFile[j],140,38))">
<cfset aEachLine["#j#"]["City"]=trim(Mid(MyFile[j],254,19))">
<cfset aEachLine["#j#"]["State"]=trim(Mid(MyFile[j],273,2))">
<cfset aEachLine["#j#"]["Country"]=trim(Mid(MyFile[j],284,4))">

<!--- run through all keys in aEachLine["#j#"] to check which ones are empty
--->
<cfset arrayCheck = StructFindValue( #aEachLine["#j#"]#, "", "all")>
<cfdump var="#arrayCheck#">
</cfloop>
alecken
2009-02-16 16:46:01 UTC
Permalink
As mentioned by BKBK, I typed in [ i ] but they did not show up here.
Thank you for all the responses and I have modified my codes per all your
suggestions.
The problem I'm still facing right now is with the checking for empty value.
If StructFindValue is checking empty value on this structure then when I dump
out this (see below) I should get some answer. All I got was an empty array
which mean none was found and this is not true.
<CFSET MyTest=StructFindValue(#stReqRecords#, "")>

Since this structure consist of all required fields, this structure can NOT
have empty element. So I need to check for empty string.

If more than one of those elements were empty I need to send email out
notifying user to send in better feed, if one of those element is empty I need
to write more code to do some further checking.
How can I check the empty element(s) from those structure? I thought
StructFindValue will do it but it did not, or I did not do it correctly?
Adam Cameron
2009-02-15 19:04:48 UTC
Permalink
Post by alecken
How do I check if any of those struct. value is empty?
Testing the length of each key's value? There's no way of checking the
whole struct in one hit; you've gotta check each key.
--
Adam
BKBK
2009-02-16 09:10:01 UTC
Permalink
Adam Cameron wrote:
[i] There's no way of checking the whole struct in one hit; you've gotta check
each key.[/i]

StructFindValue is one way. It can check the whole struct for a match to a
string value.
Adam Cameron
2009-02-16 12:11:09 UTC
Permalink
Post by BKBK
[i] There's no way of checking the whole struct in one hit; you've gotta check
each key.[/i]
StructFindValue is one way. It can check the whole struct for a match to a
string value.
Ah yes, good thinking!
--
Adam
craigkaminsky
2009-02-16 17:17:43 UTC
Permalink
alecken,

I don't think looping is the only way but suggested this approach because, I
think, you can more easily write code that determines which key in a struct is
empty (if any) and then report back to the user the issue (or do something else
such as inserting default values, etc.).

That said, since the purpose of StructFindValue is to locate any key that has
the value supplied, it should work. I just wrote and tested the following code
and it worked:
<cfscript>
myStruct = StructNew();
myStruct.key1 = "Key 1 Value";
myStruct.key2 = "Key 2 Value";
myStruct.key3 = "";

myFind = StructFindValue(myStruct,"");
</cfscript>
<cfdump var="#myFind#">

The resulting output of an array of structures showed me that key 3 was empty.

While this works to determine if there are empty keys, I would still need to
write code that determines which key was empty and then what to do from there.
I just find it easier to loop over the struct and act accordingly on each key
it finds that is empty.

This is certainly not to say that there are not other or better ways to do it;
rather, it's how I prefer to check my structs.

There are some structure functions on cflib.org that might help but in a
cursory look over the site, I did not see anything off hand.
alecken
2009-02-16 19:03:14 UTC
Permalink
craigkaminsky,
Thank you for helping. It failed to locate the key with empty value when I
tried your suggestion using StructFindValue() but when I applied trim() on the
value it is working.
<CFSET myStruct[key2] = "#Trim(Key_2_ Value#)">

One problem I'm facing right now is when there are more than 1 empty values in
the structure, StructFindValue() only point to one of them.
Using your example,
If key 1 is empty, StrucFindValue() showed me only Key1 as the one with empty
value BUT
if key1 and 3 are empty, StrucFindValue() showed me only Key3 as the one with
empty value and this is causing problem since the business rule that I have to
apply is not the same when for each scenario
craigkaminsky
2009-02-16 19:27:55 UTC
Permalink
Sorry about that. I should have noted that you need to add a third parameter to
the function (StructFindValue) to get them all.

Try this code and you'll see how it differs:
<cfscript>
myStruct = StructNew();
myStruct.key1 = "";
myStruct.key2 = "Key 2 Value";
myStruct.key3 = "";

myFind = StructFindValue(myStruct,"","all");
</cfscript>
<cfdump var="#myFind#">

I still prefer looping over the struct, checking each key and value as I loop
but by adding the third parameter "all" to the StructFindValue function will,
at least, get you an array of all matching values.
alecken
2009-02-16 20:07:11 UTC
Permalink
Oh I see, so that's what "all" and "One" attributes are for.
Now that I got all the empty elements from this structure how do I refer to
each key that has empty values so I can use cfif cfelse?
I tried to use the cfloop collection you wrote last week, I got error saying
myStruct[key]) is not a simple value so I can't use it this way

<cfloop collection="#myStruct#" item="key">
<cfif Trim(myStruct[key]) eq "">
<!--- do what you gotta here, because the key is empty --->
</cfif>
</cfloop>
BKBK
2009-02-16 21:51:18 UTC
Permalink
Alecken wrote:
[i]Now that I got all the empty elements from this structure how do I refer to
each key that has empty values so I can use cfif cfelse? [/i]

In the code I gave above, the line <cfdump var="#arrayCheck#"> gives you a
clue. Where Coldfusion matches an empty string, it creates an array of structs
with keys 'owner' and 'key'. Use the 'key' key to get the keys that correspond
to an empty string, thus

<cfif arrayLen(arrayCheck) GE 1>
<cfset emptyValuedKey = arrayCheck[1]['key']>
<p>empty-valued key: <cfoutput>#emptyValuedKey#</cfoutput></p>
</cfif>
alecken
2009-02-17 20:34:23 UTC
Permalink
I followed your suggestion and it is working great when there is only 1 empty
field.
When the array has more than 1 empty fields this code only shows one of them
even with the "all" attribute from StructFindValu():
<cfif arrayLen(arrayCheck) GE 1>
<cfset emptyValuedKey = arrayCheck[1]['key']>
<p>empty-valued key: <cfoutput>#emptyValuedKey#</cfoutput></p>
</cfif>

This is what I did to get exactly those empty fields:
First: <CFSET Result=StructFindValue(stEachLine,"")>
Then:
<CFSET GetTheStruct=Result[1]>
Then:
<CFSET GetTheCoreStruct=#GetTheStruct["owner"]#>
Then:
<cfloop collection="#GetTheCoreStruct#" item="KEY">
<cfif #Trim(GetTheCoreStruct[KEY])# EQ "">
<!--- do more things here --->
</cfif>
</cfloop>

I don't know if this is a good approach or not but so far get me what I need.
BKBK
2009-02-18 09:25:40 UTC
Permalink
Alecken wrote:
[i]I don't know if this is a good approach or not but so far get me what I need.[/i]

If it gets you what you need, then it is a good approach. Good luck.
Loading...