CFML有效地确定多个列表之一中是否存在值

时间:2015-01-30 00:39:13

标签: coldfusion

这是我发给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>

4 个答案:

答案 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>