JSONata:删除数组中第一次出现的项目

JSONata: Remove first occurrence of item in array

我想删除 JSONata 中数组中第一次出现的元素。

我试过这个:

(
    $largerArray := ["a","b","c","a","b","c"];
    $itemToExclude := "a";
    $expectedArray := ["b","c","a","b","c"];
    
    $doesNotWorkBecauseVariablesAreLocal := function($array, $element){(
        $found := false;
        $filter($array, function($v){(
            $isElem := $v = $element;
            $shouldDrop := $isElem and $not($found);
            $found := $found or $isElem;
            $not($shouldDrop)
        )})
    )};

    $doesNotWorkBecauseVariablesAreLocal($largerArray,"a");

    $reduced := $reduce($largerArray, function($acc,$arrayItem){(
        $array := $lookup($acc, "array");
        $foundAlready := $lookup($acc,"foundAlready");
        $itemToExclude := $lookup($acc,"itemToExclude");
        $shouldExclude := $arrayItem = $itemToExclude and $not($foundAlready);
        $foundAlready := $foundAlready or $shouldExclude;
        $shouldExclude ? {"array":$array, "foundAlready":$foundAlready, "itemToExclude":$itemToExclude} : {"array":$append($array,$arrayItem), "foundAlready":$foundAlready, "itemToExclude":$itemToExclude}
    )}, {"array":[], "foundAlready":false, "itemToExclude":$itemToExclude});

    $reduced.array;
)

doesNotWorkBecauseVariablesAreLocal 不起作用,因为 found 变量是局部范围的。所以我想我的问题的第一部分是:这种方法是否可行?

它似乎不起作用的事实让我尝试了第二种方法,即通过包含 arrayfoundAlready 布尔值和 [=15= 的对象携带状态]

可以用,但不够优雅。

实现这一目标的惯用 JSONata 方法是什么?

您可以使用 $reduce (https://docs.jsonata.org/higher-order-functions#reduce) 查找项目的第一次出现。 $reduce 迭代数组并传递累加器(第一个索引)以及当前索引和值。我们可以将累加器初始化为 -1,如果它仍然是 -1 并且值匹配搜索,我们 return 索引作为新的累加器值。

一旦我们有了索引,我们就可以使用 $filter (https://docs.jsonata.org/higher-order-functions#filter) 从数组中删除该索引:

(
    $largerArray := ["a","b","c","a","b","c"];
    $itemToExclude := "b";
    $expectedArray := ["b","c","a","b","c"];
    

    $dropFirst := function($array,$item){(
        $index := $reduce($array, function($accumulator, $value, $index){ $value = $item and $accumulator = -1 ? $index : $accumulator }, -1 );
        $filter($array, function($v, $i){$i != $index ? $v})
    )};

    $dropFirst($largerArray, $itemToExclude)
)

您是对的,似乎无法修改来自 outer-scope 的 $found 变量。太可惜了!

您的 reduce-based 备选方案走在正确的轨道上。 @aeberhart 打败了我,但我想出了一个非常相似的解决方案:

(
  $largerArray := ["a","b","c","a","b","c"];

  $findFirstOccurenceIndex := function($array, $itemToFind) {
    $reduce($array, function($acc, $item, $index) {
      (
        $isItemToFind := $item = $itemToFind;
        $acc != null ? $acc : $isItemToFind ? $index : null
      )
      },
      null
    )
  };

  $firstOccurence := $findFirstOccurenceIndex($largerArray, "a");
  
  $filter($largerArray, function($item, $index) { $index != $firstOccurence })
)

如果您想尝试一下,这里有一个 link to it in the JSONata Playground