Save first occurence from an array of elements

Certified Senior Developer

Hello, I need to create rule that takes an array of dictionaries in input and if multiple of these elements have the same "id" value, I want to take only the first one in a separate list:

ri!list:

{

{output: "OK, id: "abcd", description: "hello"},

{output: "OK", id: "abcd", description: "hi"},

{output: "OK", id: "yxz", description: "bye"},

{output: "OK", id: "yxz", description:"goodnight"},

{output: "OK", id: "opt", description: "ok"}

}

the output should be the following:

local!output: 

{
{output: "OK, id: "abcd", description: "hello"}, 
{output: "OK", id: "yxz", description: "bye"},
{output: "OK", id: "opt", description: "ok"}
}


  Discussion posts and replies are publicly visible

Parents
  • I usually tackle this by breaking it down into pseudocode that describe successive steps of the process, then replacing those with local variables that handle that step (and abstract the functionality behind that variable, which helps in dev and debugging etc).

    Here goes my quick "first pass":

    1. take the initial array and pass the IDs through my "distinct" helper rule to get a list of unique IDs  ("distinct" is usually just an expression rule that calls union() on the input rule input, repeated)
    2. iterate over that list of IDs and get lists of indexes of the index locations in the initial dictionary for the current id ("wherecontains()")
    3. (can possibly be done at the same moment as step 2) - narrow down to just the first index for each item
    4. call index() on the original dictionary array, passing in the narrowed-down index values, to produce the initial list entries for each ID

    Edit: merely for the sake of curiosity, I timed myself at 3 minutes, 4 seconds to translate the above steps into code and whip up this:

    a!localVariables(
      
      local!initialDict: {
        {output: "OK", id: "abcd", description: "hello"},
        {output: "OK", id: "abcd", description: "hi"},
        {output: "OK", id: "yxz", description: "bye"},
        {output: "OK", id: "yxz", description:"goodnight"},
        {output: "OK", id: "opt", description: "ok"}
      },
    
      local!uniqueIds: rule!RULE_General_distinct(array: local!initialDict.id),  /* just does a "union()" on ri!array, on itself, quickly eliminating duplicates */
      
      local!indices: a!forEach(
        local!uniqueIds,
        index(
          wherecontains(fv!item, touniformstring(local!initialDict.id)),
          1,
          {}
        )
      ),
      
      index(
        local!initialDict,
        local!indices
      )
    )

Reply
  • I usually tackle this by breaking it down into pseudocode that describe successive steps of the process, then replacing those with local variables that handle that step (and abstract the functionality behind that variable, which helps in dev and debugging etc).

    Here goes my quick "first pass":

    1. take the initial array and pass the IDs through my "distinct" helper rule to get a list of unique IDs  ("distinct" is usually just an expression rule that calls union() on the input rule input, repeated)
    2. iterate over that list of IDs and get lists of indexes of the index locations in the initial dictionary for the current id ("wherecontains()")
    3. (can possibly be done at the same moment as step 2) - narrow down to just the first index for each item
    4. call index() on the original dictionary array, passing in the narrowed-down index values, to produce the initial list entries for each ID

    Edit: merely for the sake of curiosity, I timed myself at 3 minutes, 4 seconds to translate the above steps into code and whip up this:

    a!localVariables(
      
      local!initialDict: {
        {output: "OK", id: "abcd", description: "hello"},
        {output: "OK", id: "abcd", description: "hi"},
        {output: "OK", id: "yxz", description: "bye"},
        {output: "OK", id: "yxz", description:"goodnight"},
        {output: "OK", id: "opt", description: "ok"}
      },
    
      local!uniqueIds: rule!RULE_General_distinct(array: local!initialDict.id),  /* just does a "union()" on ri!array, on itself, quickly eliminating duplicates */
      
      local!indices: a!forEach(
        local!uniqueIds,
        index(
          wherecontains(fv!item, touniformstring(local!initialDict.id)),
          1,
          {}
        )
      ),
      
      index(
        local!initialDict,
        local!indices
      )
    )

Children