access the index of the item inside reduce function in dataweave 2.0 - mule

My DataWeave code looks like below:-
Result: Data reduce (item,ls={}) -> ls ++ From: {dev: item.warehouse}
Is there way to check the index of item object. I need to do conditional based on the index of the item object.
Example:
Item = Data[0] do this ;
Result: Data reduce (item,ls={}) -> ls ++ From: {dev: item.warehouse}
Item = Data[1] do this ;
Result: Data reduce (item,ls={}) -> ls ++ To: {dev: item.warehouse}
Original Code looks like below:
Result : ( Data reduce (
item,ls={}) -> ls ++
From:{id: "111",(if (item.sign == "333") {status: "OPEN"} else if (item.sign == "444") {status: "HOLD"} else {status: item.sign})}
I need to add "From" whenever the index of Item is odd number and add "To" whenever the index of item is even.
Since I don't have the conditional, I am always getting "From"

No you can't access any indexes, here's the documentation of reduce https://docs.mulesoft.com/mule-runtime/4.1/dw-core-functions-reduce
What you can do is count the items yourself by modifying the structure of your accummulator: ls={counter=0,data={}}
Now you can use the counter to add one per iteration and keep track of things: {counter: ls.counter + 1, data: ls.data ++ To: {dev: item.warehouse}}
As you can understand you would need to add a conditional to differentiate between the From and To.
If I have time later on I 'll do it for you, or somebody else can beat me to it.
EDIT: here's the best I can do based upon your question, but you should get the idea:
%dw 2.0
output application/dw
var inputdata = [{warehouse: 100},{warehouse: 56}, {warehouse:1000}]
---
inputdata reduce (
(e, acc={c: 0, data: {From: {}, To: {}}}) ->
{
c: acc.c+1,
data: {
From: if (isEven(acc.c)) (acc.data.From ++ {warehouse: e.warehouse}) else acc.data.From,
To: if (isEven(acc.c)) acc.data.To else (acc.data.To ++ {warehouse: e.warehouse})
}
}
)
Always provide appropriate sample inputs and outputs of your transformation if you want to get the most out of the DW SO community ;)

Related

How to get size of specfic value inside array Kotlin

here is example of the list. I want to make dynamic where maybe the the value will become more.
val list = arrayListOf("A", "B", "C", "A", "A", "B") //Maybe they will be more
I want the output like:-
val result = list[i] + " size: " + list[i].size
So the output will display every String with the size.
A size: 3
B size: 2
C size: 1
If I add more value, so the result will increase also.
You can use groupBy in this way:
val result = list.groupBy { it }.map { it.key to it.value.size }.toMap()
Jeoffrey's way is better actually, since he is using .mapValues() directly, instead of an extra call to .toMap(). I'm just leaving this answer her since
I believe that the other info I put is relevant.
This will give a Map<String, Int>, where the Int is the count of the occurences.
This result will not change when you change the original list. That is not how the language works. If you want something like that, you'd need quite a bit of work, like overwriting the add function from your collection to refresh the result map.
Also, I see no reason for you to use an ArrayList, especially since you are expecting to increase the size of that collection, I'd stick with MutableList if I were you.
I think the terminology you're looking for is "frequency" here: the number of times an element appears in a list.
You can usually count elements in a list using the count method like this:
val numberOfAs = list.count { it == "A" }
This approach is pretty inefficient if you need to count all elements though, in which case you can create a map of frequencies the following way:
val freqs = list.groupBy { it }.mapValues { (_, g) -> g.size }
freqs here will be a Map where each key is a unique element from the original list, and the value is the corresponding frequency of that element in the list.
This works by first grouping elements that are equal to each other via groupBy, which returns a Map<String, List<String>> where each key is a unique element from the original list, and each value is the group of all elements in the list that were equal to the key.
Then mapValues will transform that map so that the values are the sizes of the groups instead of the groups themselves.
An improved approach, as suggested by #broot is to make use of Kotlin's Grouping class which has a built-in eachCount method:
val freqs = list.groupingBy { it }.eachCount()

difference between two lists that include duplicates

I have a problem with two lists which contain duplicates
a = [1,1,2,3,4,4]
b = [1,2,3,4]
I would like to be able to extract the differences between the two lists ie.
c = [1,4]
but if I do c = a-b I get c =[]
It should be trivial but I can't find out :(
I tried also to parse the biggest list and remove items from it when I find them in the smallest list but I can't update lists on the fly, it does not work either
has anyone got an idea ?
thanks
You see an empty c as a result, because removing e.g. 1 removes all elements that are equal 1.
groovy:000> [1,1,1,1,1,2] - 1
===> [2]
What you need instead is to remove each occurrence of specific value separately. For that, you can use Groovy's Collection.removeElement(n) that removes a single element that matches the value. You can do it in a regular for-loop manner, or you can use another Groovy's collection method, e.g. inject to reduce a copy of a by removing each occurrence separately.
def c = b.inject([*a]) { acc, val -> acc.removeElement(val); acc }
assert c == [1,4]
Keep in mind, that inject method receives a copy of the a list (expression [*a] creates a new list from the a list elements.) Otherwise, acc.removeElement() would modify an existing a list. The inject method is an equivalent of a popular reduce or fold operation. Each iteration from this example could be visualized as:
--inject starts--
acc = [1,1,2,3,4,4]; val = 1; acc.removeElement(1) -> return [1,2,3,4,4]
acc = [1,2,3,4,4]; val = 2; acc.removeElement(2) -> return [1,3,4,4]
acc = [1,3,4,4]; val = 3; acc.removeElement(3) -> return [1,4,4]
acc = [1,4,4]; val = 4; acc.removeElement(4) -> return [1,4]
-- inject ends -->
PS: Kudos to almighty tim_yates who recommended improvements to that answer. Thanks, Tim!
the most readable that comes to my mind is:
a = [1,1,2,3,4,4]
b = [1,2,3,4]
c = a.clone()
b.each {c.removeElement(it)}
if you use this frequently you could add a method to the List metaClass:
List.metaClass.removeElements = { values -> values.each { delegate.removeElement(it) } }
a = [1,1,2,3,4,4]
b = [1,2,3,4]
c = a.clone()
c.removeElements(b)

IF statement into another IF statement DW 2.0

var lnc_id = []
output application/java
---
if (payload.success contains true and payload.accepted contains true)
{
if (lnc_id contains vars.payload_json.data.LNC_ID)
{
lnc_id + lnc_id contains vars.payload_json.data.LNC_ID
}
}
I'm writing and Api with Mulesoft and I need an IF inside another IF, the language is Datawave 2.0.
The error is:
"Invalid input "f ", expected Namespace "
You script has several issues:
{} denotes an object, you need to
use attributes inside an object instead of expressions.
Each if has to have an else clause.
lnc_id will
not preserve values between executions, so it will always start as an
empty array (this might be expected but I wanted to clarify it just in case).
This is a simpler example of how to nest if...else
var list = []
var success = true
output application/java
---
if (success == true )
if (3 > 2)
( list + "something")
else null
else null

How to use $setOnInsert field in ReactiveMongo?

I'm trying to include the $setOnInsert field for Update and FindAndModify in ReactiveMongo. However, I can't seem to get it to work with the built in Commands.
Does anyone know how to include this field for updating a document?
This simple example works for me:
val collection = ... // your collection goes here
collection.update(
obj("_id" -> "1"),
obj(
"$setOnInsert" -> obj("field 1" -> "value 1"),
"$set" -> obj("field 2" -> "value 2")),
upsert = true
).map {
case n => println(n.ok.toString) // do smth
}

Grails query rows to arrays

I'm new to Groovy and Grails. I think this problem probably has an easy answer, I just don't know it.
I have a database table:
id | category | caption | image | link
I have a query that lets me retrieve one row for each distinct item in 'category.'
I'm trying to return a map where each row is an array named by it's category.
e.g., If I select the rows:
[{category='foo', caption='stuff', ...} {category='bar', caption='things', ...}]
I want to be able to:
return [foo:foo, bar:bar]
where:
foo = [caption='stuff', ...]
bar = [caption='things', ...]
Thanks for any help.
You can transform your list using collect in Groovy, however, the result depends on the source data. I could not infer from your post that if you are returning one item per category or multiple.
def ls = Category.list()
def newList = ls.collect {
[(it.category):['caption':it.caption,'image':it.image,'link':it.link]]
}
will result in something like :
[
[bar:[caption:BarCaption-2, image:BarImage-2, link:BarLink-2]],
[bar:[caption:BarCaption-1, image:BarImage-1, link:BarLink-1]],
[bar:[caption:BarCaption-0, image:BarImage-0, link:BarLink-0]],
[foo:[caption:FooCaption-2, image:FooImage-2, link:FooLink-2]],
[foo:[caption:FooCaption-1, image:FooImage-1, link:FooLink-1]],
[foo:[caption:FooCaption-0, image:FooImage-0, link:FooLink-0]]
]
If you have multiple items per each category you probably want to return the list of each.
def bars = newList.findAll { it.containsKey 'bar' }
def foos = newList.findAll { it.containsKey 'foo' }
[foos:foos,bars:bars]
If I understand your question correctly (I think you mean to put ':' instead of '=' for your maps) then I think the following will work. If new to Groovy, you might find the Groovy web console at http://groovyconsole.appspot.com/ useful. You can try snippets of code out easily, like the following:
def listOfMaps = [[category:'foo', caption:'stuff', something:'else'], [category:'bar', caption:'things', another:'thing']]
def mapOfMaps = [:]
listOfMaps.each { mapOfMaps += [(it.remove('category')) : it] }
assert mapOfMaps == [foo:[caption:'stuff', something:'else'], bar:[caption:'things', another:'thing']]