试图获取数组中结构的值

trying to get the value of the struct inside an array

正在 java 或 cfm 中寻找单行代码,我不需要循环结构数组来使用 structfind 从中获取值。

现在正在看,

Coldfusion - How to loop through an Array of Structure and print out dynamically all KEY values?

我可以在哪里循环并获取键匹配的值

但正在尝试检查这样的事情是否可以完成

<cfset myvalue = structfindvaluefromAnything(myarrayofstruct,"infor")>

我相信为此提供的功能几乎正是您所希望的...

StructFindValue(struct, value [, scope])

在嵌套数组、结构和其他元素的子结构中递归搜索其值与值参数中的搜索关键字匹配的结构。

Returns 包含结构键的数组,其值与搜索键值匹配。如果找到 none,returns 一个大小为 0 的数组。

如果你真的想在一行中完成,那么你可以结合使用 ArrayFilter()StructFindValue()

改编自 ArrayFilter 的 Adob​​e 文档 - https://helpx.adobe.com/coldfusion/cfml-reference/coldfusion-functions/functions-a-b/arrayfilter.html - 类似这样的内容:

<cfscript>
     superheroes=[
           {"name":"Iron Man","member":"Avengers"},
           {"name":"Wonder Woman","member":"Justice League"},
           {"name":"Hulk","member":"Avengers"},
           {"name":"Thor","member":"Avengers"},
           {"name":"Aquaman","member":"Justice League"}
     ];
 
    avengers=ArrayFilter(superheroes,function(item){ 
        return ArrayLen(StructFindValue( item, "Avengers"));
    });
    writeDump(var=avengers, label="all matches");

    writeDump(var=ArrayLen(avengers) ? avengers[1] : "Not found", label="first match only");

    writeDump(var=structFindValue({"a":superheroes}, "Avengers", "all"), label="without arrayFilter");
</cfscript>

我喜欢 Sev 的方法。我会稍微改变一下

<cfscript>
     superheroes=[
           {"name":"Iron Man","member":"Avengers"},
           {"name":"Spider-Man","member":"Avengers"},
           {"name":"Wonder Woman","member":"Justice League"},
           {"name":"Hulk","member":"Avengers"},
           {"name":"Thor","member":"Avengers"},
           {"name":"Aquaman","member":"Justice League"}
     ];
 
     avengers = superheroes.filter(function(item) { 
        return item.member ==  "Avengers";
    });
     writeDump(avengers);
</cfscript>

根据您上面提供的要点 (https://cffiddle.org/app/file?filepath=3e26c1ac-d5db-482f-9bb2-995e6cabe704/49b3e106-8db9-4411-a6d4-10deb3f8cb0e/24e44eba-45ef-4744-a6e6-53395c09a344.cfm),我认为您已经稍微阐明了您的期望。

在您的要点中,您说您希望能够搜索结构数组并找到具有 "name" 键且值为 "form" 的行。然后,您想要获取与数组行中的该结构关联的 "value" 键的值。如果没有 value 那么 return 0.

您希望能够在一行代码中完成此操作,而上述答案确实实现了这一点。我的回答基本上建立在这些基础上。

如前面的答案所示,您仍然希望使用闭包函数来过滤最终输出。这些速度非常快,本质上是为了完成您想要做的事情而构建的。

我合作过的Fiddle在这里:https://cffiddle.org/app/file?filepath=b3507f1d-6ac2-4900-baed-fb3faf5a3b3a/e526afc2-bb85-4aea-ad0e-dcf38f52b642/75d88d2b-f990-44c1-9d9f-22931bf9d4d7.cfm

我用这个做了两件事。

首先,我的工作方式就好像您希望遇到多个记录作为您的过滤值,然后将它们变成一个 comma-delimited 列表。如果您需要其他结构,可以修改我代码中的 reduce() 函数来处理此问题。

其次,我按照您预期只会遇到一个过滤记录的方式进行工作,return只会遇到一个值。

我做的第一件事(这在两种方法中基本相同,并且与之前的答案基本相同)是过滤原始数组以获得您想要的值。

这样做是这样的:

myResult = originalArray.filter( 
    function(itm){ 
        return itm?.name=="form";   /// ?. = safe-navigation operator.
    } 
)

为了清楚起见,我将其分为多行。

这将 return 一个由过滤行组成的新结构数组。

但是你想从这些行中获取这些记录和 return "value"(如果没有值,默认为 0。你可以使用 reduce().

commaDelimitedValue = 
    myResult.reduce( 
        function(prev,nxt) { 
            return prev.listappend( ( nxt.value.len() ? nxt.value : 0 ) ) ;
        }
        , ""   /// Initialization value 
    ) ;

同样,这可以写在一行中,但为了清楚起见,我添加了换行符。

reduce() 函数本质上只是将您的输入减少为单个值。它遵循 .reduce( function( previousValue, nextValue ){ return .... },<initializationValue>) 的格式,其中,在第一次迭代中,initializationValue 被替换为 previousValue,然后 previousValue 成为该迭代的结果。 nextValue 实际上是您将从中得出结果的当前迭代。

更多信息位于:https://coldfusion.adobe.com/2017/10/map-reduce-and-filter-functions-in-coldfusion/

在我这里的假设中,您可能 return 从您的 filter() 编辑了多行。您获取这些行并将 value 附加到 commma-delimited 列表。所以你最终会得到像 20,10,0,0 这样的结果 - 在你的过滤结果中代表 4 行。

我还检查 value 的长度,如果它是空字符串,则默认为 0。上面,我说过你可以只使用 Elvis 运算符 (:?),但这不适用于像空字符串这样的简单值。 Elvis 使用 NULLs,早期的数组确实有。

要将其放回一行,您可以将这两个函数链接起来。所以你最终得到:

myFinalResult =  
    myOriginalArray.filter( 
        function(itm){ 
            return itm?.name=="form";
        } 
    )
    .reduce(   
        function(prev,nxt) { 
            return prev.listappend( ( nxt.value.trim().len() ? nxt.value : 0 ) ) ;
        }
        , ""
    ) 
;

同样,该代码做了很多工作,但本质上仍然是一行。最终结果将再次类似于 "20,10,0,0" 4 行,其中 2 行默认为 0.

如果您只希望过滤器 return 单行,或者如果您只需要一个值,则可以稍微简化一下。

myFinalResult = myOriginalArray.filter( function(itm){ return itm?.name=="fm" && (itm?.value.trim().len()>0) ; } )[1]["value"] ?: 0 ;

有了这个,我又回到了使用我之前与 Elvis 的技巧来默认没有 value 的行,因为我用 empty-string "form" 过滤掉结构 "value"&&AND 相同。从技术上讲,这个 CAN 从原始数组中过滤多行,但 [1] 只会从过滤的行中选择第一行。它也不需要使用 reduce()。如果过滤了不止一行,每次迭代只会覆盖前一行。

这将 return 一个简单的单一值,类似于 42 - 这是数组中最后过滤的值,因为它会覆盖前一行的值。

我的 Fiddle (https://cffiddle.org/app/file?filepath=b3507f1d-6ac2-4900-baed-fb3faf5a3b3a/e526afc2-bb85-4aea-ad0e-dcf38f52b642/75d88d2b-f990-44c1-9d9f-22931bf9d4d7.cfm) 有一些额外的评论,我设置了几个边缘案例来演示过滤和 safe-navigation.


我还要重申一下,如果这是 Lucee 5+ 或 ACF2018+,您可以使用 Arrow Functions 进一步缩短它。