这是我发给SO的第一篇文章,这是一种非常有价值的资源!
我正在尝试确定代码列表中是否存在值(状态代码),如果存在,则设置表示分部的新变量(即销售区域,不匹配= 15)。下面的代码有效,但我想提高自己的技能并尽可能高效地完成这项工作。所以我的问题是有一种“更好”的方法来实现相同的结果吗?
<cfset state = "LA">
<cfset division = 15>
<cfset position = 0>
<cfset aStates = ArrayNew(1)>
<cfset aStates[1] = "MA,ME,NH,RI,VT">
<cfset aStates[2] = "CT,DE,NJ,NY,DE">
<cfset aStates[3] = "DC,MD,VA,WV">
<cfset aStates[4] = "TN">
<cfset aStates[5] = "NC,SC">
<cfset aStates[6] = "GA">
<cfset aStates[7] = "FL">
<cfset aStates[8] = "AL,KY,LA,MS">
<cfset aStates[9] = "IL,WI">
<cfset aStates[10] = "CO,MN,ND,SD,WY">
<cfset aStates[11] = "IN,OH,MI">
<cfset aStates[12] = "ID,OR,UT,WA">
<cfset aStates[13] = "AZ,HI,NV">
<cfset aStates[14] = "CA">
<cfset position = 0>
<cfloop array="#aStates#" index="lStates">
<cfset position = position+1>
<cfif ListFindNoCase(lStates,variables.state) NEQ 0>
<cfset division = position>
</cfif>
</cfloop>
<cfdump var="#aStates#" label="states array">
<cfoutput>State: #state#</cfoutput>
<cfoutput>Division: #division#</cfoutput>
答案 0 :(得分:4)
使用当前结构,您依赖于字符串比较,因此没有太多改进空间。
除非有特定原因您必须对值进行硬编码,否则更灵活的方法是将信息存储在数据库中。创建表来存储&#34;状态&#34;和&#34; divisions&#34;,以及另一个存储关系的表:
States
StateID | Code | Name
1 | ME | Maine
2 | GA | Georgia
3 | CA | California
4 | NH | New Hampshire
...
Divisions
DivisionID | Name
1 | Sales Territory
...
DivisionStates
DivisionID | StateID
1 | 1
1 | 4
6 | 2
14 | 3
...
然后使用OUTER JOIN检索选定的状态和除法。假设#state#
将始终包含有效条目,则沿着这些行(未经测试):
SELECT s.Name AS StateName
, CASE WHEN d.Name IS NULL THEN 'No Match' ELSE d.Name END AS DivisionName
FROM States s
LEFT JOIN DivisionStates ds ON ds.StateID = s.StateID
LEFT JOIN Divisions d ON d.DivisionID = ds.DivisionID
WHERE s.Code = <cfqueryparam value="#state#" cfsqltype="cf_sql_varchar">
我不知道#state#
变量的来源,但我猜它可以通过表单<select>
传递。如果它当前是硬编码的,你可以通过查询&#34;状态&#34;来进一步简化事情。表,并使用它来填充列表。另外,请考虑使用ID作为列表值,而不是状态&#34;代码&#34;。
答案 1 :(得分:1)
通过将状态放入Struct中,我想到了一种方法;将州代码作为密钥。
<cfscript>
state = "LA";
division = 15;
states_divisions_map = {
MA: 1, ME: 1, NH: 1, RI: 1, VT: 1,
CT: 2, NJ: 2, NY: 2, DE: 2,
DC: 3, MD: 3, VA: 3, WV: 3,
TN: 4,
NC: 5, SC: 5,
GA: 6,
FL: 7,
AL: 8, KY: 8, LA: 8, MS: 8,
IL: 9, WI: 9,
CO: 10, MN: 10, ND: 10, SD: 10, WY: 10,
IN: 11, OH: 11, MI: 11,
ID: 12, OR: 12, UT: 12, WA: 12,
AZ: 13, HI: 13, NV: 13,
CA: 14
};
if(StructKeyExists (states_divisions_map, state) ){
division = states_divisions_map[state];
}
writeDump(var: states_divisions_map, label: "States");
writeOutput("State: #state#");
writeOutput("Division: #division#");
</cfscript>
通过这种方式,您可以快速检查没有所有循环的状态。
观察:在原始代码中,DE
出现两次。
答案 2 :(得分:1)
ListContains()
与ListFind()
类似,但它会搜索一个列表元素,其中包含您在其中任何位置查找的文字。 (ListFind()
查找与字符串完全匹配的列表元素。通常ListFind()
是更好的工具,但在这种情况下不是。
(CF确实有一个ArrayContains,但它不适用于此任务,它只是告诉你数组是否包含完全匹配的元素。)
因为您正在搜索唯一的双字符状态代码,所以这是该功能的完美使用。
<cfset aStates = ArrayNew(1)>
<cfset aStates[1] = "MA,ME,NH,RI,VT">
<cfset aStates[2] = "CT,DE,NJ,NY,DE">
<cfset aStates[3] = "DC,MD,VA,WV">
<cfset aStates[4] = "TN">
<cfset aStates[5] = "NC,SC">
<cfset aStates[6] = "GA">
<cfset aStates[7] = "FL">
<cfset aStates[8] = "AL,KY,LA,MS">
<cfset aStates[9] = "IL,WI">
<cfset aStates[10] = "CO,MN,ND,SD,WY">
<cfset aStates[11] = "IN,OH,MI">
<cfset aStates[12] = "ID,OR,UT,WA">
<cfset aStates[13] = "AZ,HI,NV">
<cfset aStates[14] = "CA">
<cfset lstates = arraytolist(astates,"|")>
<cfset division = listcontainsnocase(lstates,"CO","|")>
<cfoutput>Division: #division#<br>
State: #state#</cfoutput>
我们将分隔符设置为| (管道),但你可以使用除默认(逗号)之外的任何东西,因为你正在使用它作为你的子分隔符。
为了将来参考,如果您使用CF 9(我相信)或之后,您可以使用数组速记来快速构建数组。
<cfset aStates=["MA,ME,NH,RI,VT","CT,DE,NJ,NV,DE","DC,MD,VA,WV"]> ...
虽然看起来似乎只是风格差异,但它可以节省大量时间。
可以类似地创建结构。
<cfset MyDogIs = {Size = "medium", Color = "Black", HasPaws = ["FL","FR","BL","BR"]}>
(你可以将隐式数组和结构嵌套在另一个中!)
答案 3 :(得分:0)
谢谢大家的意见。我自己用我决定使用的代码回答这个问题,因为它基于多个答案/评论提供的部分。我希望这是正确的方法,如果没有请建议。
这些分区没有存储在数据库中,因为它们是一个设置它并且忘记了多年来没有改变的映射,我以为我会保存对数据库的调用。如果它们可能会发生变化,我会采取@leigh
建议的表格方法感谢@ matt-busche提供改进的循环,ucase()和break建议,以及@cfqueryparam用于简短的数组建议。
这就是我的用途。代码实际上是cfc中处理表单提交的函数,但我只粘贴了相关部分。
<cfset form.division = 15>
<cfset aDivisions = ["MA,ME,NH,RI,VT",
"CT,DE,NJ,NY,DE",
"DC,MD,VA,WV",
"TN",
"NC,SC",
"GA",
"FL",
"AL,KY,LA,MS",
"IL,WI",
"CO,MN,ND,SD,WY",
"IN,OH,MI",
"ID,OR,UT,WA",
"AZ,HI,NV",
"CA"]>
<cfloop from="1" to="#ArrayLen(aDivisions)#" index="i">
<cfif ListFind(aDivisions[i],Ucase(arguments.sForm.state)) NEQ 0>
<cfset form.division = i>
<cfbreak>
</cfif>
</cfloop>