【问题标题】:How to update the max loop length if the length gets smaller in the loop body?如果循环体中的长度变小,如何更新最大循环长度?
【发布时间】:2009-07-07 15:32:56
【问题描述】:

我有以下数组。

<cfset ItemHasUsers = arrayNew(1)>
<cfloop query="qReadData">
 <cfset ItemHasUsers[qReadData.currentrow]["ID"] = qReadData.ID >
 <cfset ItemHasUsers[qReadData.currentrow]["Asset"] = qReadData.COUNTOFITEMS >
</cfloop>

我从我的数据库中获取了一些记录,我将它们放入一个表中并通过一个表单进行操作。

<form action="same-site.cfm method="post">
<table>
 <tr>
  <th>ID</th>
  <th>Asset</th>
  <th>Delete</th>
 <tr>
<cfset ItemHasUsers = Item.getItemHasUsers() >
<cfoutput>
<cfloop index="i" from="1" to="#arrayLen(ItemHasUsers)#">
  <td>#ItemHasUsers[i]["ID"]#</td>
  <td><input type="text" name="upd_#ItemHasUsers[i]["ID"]#" maxlength="6" size="6" value="#ItemHasUsers[i]["Asset"]#"></td>
  <td><input type="checkbox" name="del_#ItemHasUsers[i]["ID"]#"></td>
 </tr>
</cfloop>
</cfouput>
</table>
<input type="submit" value="OK">
</form>

取决于我的输入,我想更新我的数据库。 目前我循环遍历表单结构以清除我要删除的用户。看起来很难看,但我不知道更好的方法 -> 观看初学者标签;)

<cfset ItemHasUsers = Item.getItemHasUsers() >
<cfloop collection="#form#" item="key">
 <cfif left(key,len("DEL_")) eq ("DEL_")>
  <cfset Id = listLast(key,"_") >
  <cfloop index="i" from="1" to="#arrayLen(ItemHasUsers)#">
   <cfif ItemHasUsers[i]["ID"] eq Id>
    <cfset structClear(ItemHasUsers[i]) >
   </cfif>
  </cfloop>
 </cfif>
</cfloop>

<cfset ItemHasUsers = Item.getItemHasUsers() >
<cfloop index="i" from="1" to="#arrayLen(ItemHasUsers)#">
 <cfif ItemHasUsers[i]["ID"] eq Id>
  <cfset arrayDeleteAt(ItemHasUsers,i) >
 </cfif>
</cfloop>

这仅在我检查输入表单中的最后一个元素是否删除时才有效。如果我检查任何其他我得到以下错误

找不到数组变量“ITEMHASUSERS”的第 1 维位置 3 的元素。

好的,arrayDeleteAt 调整数组大小并自动删除间隙。如何更新下一次迭代的循环长度?

【问题讨论】:

  • 我不确定 ItemHasUsers 的用途。你为什么要经历所有这些麻烦来构建这个数据结构?例如,在您注意到其中一项已设置为“DEL”之后,您将如何处理它? 再次循环它以从数据库中删除该项目?
  • 我有一个数据对象,它有字段(它的 id、它的名字)和一个数组。在每个数组位置中,我创建一个包含与数据对象相关的数据的结构(以获取具有命名索引的关联数组而不是二维数组)。在我的代码中,来自数据库的唯一商品或文章由不同的用户出售,其中每个人都拥有所述商品的不同资产。如果我更改某些内容并想要保存更改,则数据对象是我在将其数据写回数据库之前对该项目的临时存储。

标签: arrays coldfusion loops


【解决方案1】:

这样做的诀窍是向后逐步遍历数组。从最后一个元素开始循环到第一个元素,这样您就不会在从数组中删除项目后尝试引用超过数组长度的元素。

<cfset ItemHasUsers = Item.getItemHasUsers() >
<cfloop index="i" from="#arrayLen(ItemHasUsers)#" to="1" step="-1">
 <cfif ItemHasUsers[i]["ID"] eq Id>
  <cfset arrayDeleteAt(ItemHasUsers,i) >
 </cfif>
</cfloop>

【讨论】:

  • 你最终会检查一些项目两次,否则就是 +1
  • 第二个循环中的变量 Id(您在此处显示?)总是具有相同的值 - 无论它从第一个循环中完成。
【解决方案2】:

不要这样做:

<input type="checkbox" name="del_#ItemHasUsers[i]["ID"]#">

这样做:

<input type="checkbox" name="del" value="#ItemHasUsers[i]["ID"]#">


然后,您可以这样做:

<cfloop index="i" from="#ArrayLen(ItemHasUsers)#" to="1" step="-1">
    <cfif ListFind(Form.Del,ItemHasUsers[i].Id)>
        <cfset ArrayDeleteAt(ItemHasUsers,i)/>
    </cfif>
</cfloop>


或者更好的是,停止将查询转换为结构数组,您可以更轻松地做到这一点:

<cfquery name="ItemHasUsers" dbtype="Query">
    SELECT id , assets
    FROM ItemHasUsers
    WHERE id NOT IN (<cfqueryparam list value="#Form.Del#" cfsqltype="cf_sql_integer"/>)
</cfquery>

不需要循环!

【讨论】:

  • 这个选项似乎是最简单的。 (只是“列表”属性语法上的一个小错字)。
  • 对于布尔属性,仅指定属性名称是有效的,作为list="true" 的简写。
  • 我从来不知道那个!好的提示彼得。
  • cfqueryparam 需要在括号内。请注意,Oracle 对 IN 子句有 1000 项的硬性限制。
  • 啊!我总是忘记括号。应该由 cfqueryparam 自动插入!由于这是 QoQ,Oracle 的限制不会在这里适用 - 有谁知道 CF 查询引擎是否有类似的限制?
【解决方案3】:

Jayson 的回答大概就是我会怎么做。

另一种方法是使用条件循环并保留自己的计数器。条件是您的计数器小于或等于数组的长度。

<cfset counter=1 />
<cfloop condition="#counter LTE arrayLen(myArray)#">
    <cfif iNeedToDelete>
        <cfset arrayDeleteAt(myArray,counter) />
    <cfelse>
        <cfset counter=counter+1 />
    </cfif>
</cfloop>

但是,坦率地说,杰森的回答更简单、更清晰。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-06-28
    • 2014-05-26
    • 1970-01-01
    • 1970-01-01
    • 2021-10-25
    • 2018-08-30
    • 1970-01-01
    相关资源
    最近更新 更多