Alex
Alex

Reputation: 4473

Mule 4: DW2 - Array of objects, distinct by object field

I want an array of objects that are distinct by a certain field. The array is already sorted by this field so identifying which fields to remove should follow this: the value of the previous field should be different from current value of the field.

For example, this array

[{A:'1',B:'1'},{A:'2',B:'2'},{A:'2',B:'3'}]

should transform to

[{A:'1',B:'1'},{A:'2',B:'2'}]

I tried the following:

%dw 2.0
output application/json
var payload=[{A:'1',B:'1'},{A:'2',B:'2'},{A:'2',B:'3'}]
---
(payload map (  
    (a,i) ->   ( (a) if payload[i-1].A != $.A  ) 
))

but it does not work. If I do not use the current item ($) then it works like this

 (a,i) ->   ( (a) if payload[i-1].A != '2'  ) 

But I need the current and previous items to be present to determine that current item is new (not equal for previous one).

Upvotes: 0

Views: 4071

Answers (2)

vikram92
vikram92

Reputation: 94

I will give a more general answer that will not only distinct by 'A' but also distinct by 'B' because it is not clear in the question wording if doing distinct by only 'A' is enough. Although your dataweave tries to distinct only by 'A', your example has only two equal As and no two equal Bs - which is one specific case. So I will assume that no two As should be equal and no two Bs should be equal.

Some examples with desired outputs:

Example(i): [{A:'1',B:'1'},{A:'2',B:'2'},{A:'3',B:'2'}] -> [{A:'1',B:'1'},{A:'2',B:'2'}]
Example(ii): [{A:'1',B:'1'},{A:'2',B:'2'},{A:'2',B:'2'}] -> [{A:'1',B:'1'},{A:'2',B:'2'}] 
Example(iii): [{A:'1',B:'1'},{A:'2',B:'2'},{A:'2',B:'3'}] -> [{A:'1',B:'1'},{A:'2',B:'2'}]
Example(iv): [{"A":'1',"B":'1'},{"A":'2',"B":'2'},{"A":'3',"B":'2'},{"A":'2',"B":'2'}] ->  [{A:'1',B:'1'},{A:'2',B:'2'}]
  1. One might be tempted to do arr distinctBy ($.A + $.B). But this would work only in the case of example(ii) because it will distinct by combined A and B. Example(i) and example(iii) will remain unchanged. Example(iv) will transform to [{"A":'1',"B":'1'},{"A":'2',"B":'2'},{"A":'3',"B":'2'}] .
  2. So to achieve stated goal of no two As are equal and no two Bs are equal, we have to first distinct by 'A', then distinct by 'B' and then find the common overlapping array between the two. So I am using filter and contains to achieve this like below:
%dw 2.0
output application/json
var arr = [{"A":'1',"B":'1'},{"A":'2',"B":'2'},{"A":'3',"B":'2'}]
---
(arr distinctBy $.A) filter ((arr distinctBy $.B) contains $)

Upvotes: 1

jerney
jerney

Reputation: 2233

You should be able to ignore the fact that your array is sorted: you don't need the convenience of knowing the current value is distinct from the previous. You can use distinctBy instead:

%dw 2.0
output application/json

var arr = [{A:'1',B:'1'},{A:'2',B:'2'},{A:'2',B:'3'}]
---
arr distinctBy $.A

Returns

[
  {
    "A": "1",
    "B": "1"
  },
  {
    "A": "2",
    "B": "2"
  }
]

Here are the docs for distinctBy if you're interested: https://docs.mulesoft.com/mule-runtime/4.1/dw-core-functions-distinctby

Upvotes: 3

Related Questions