2

With the following input:

[5,5,4,4,4,2,2,1]

I want to generate the following output:

[
  {
    "points": 5,
    "rank": 1
  },
  {
    "points": 5,
    "rank": 1
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 2,
    "rank": 6
  },
  {
    "points": 2,
    "rank": 6
  },
  {
    "points": 1,
    "rank": 8
  }
]

I found a solution (see the response) but I wonder if is there a better way to do it.

  • Hey Sebastien, could you please explain the algorithm in English on how a rank is calculated? – George Nov 13 '20 at 12:12

4 Answers4

5

I am not sure if this covers all your test cases, but here's a shorter version of code that I came up with-

%dw 2.0
import * from dw::core::Arrays
output application/json
var inp=[5,5,4,4,4,2,2,1]
---
inp map (v0,k0) ->
{
    points:v0,
    rank:indexOf(inp,v0)+1
}

Please let me know what you think.

TheOtherGuy
  • 184
  • 2
  • 9
  • Nicely done, now put a space between `map` and the lambda expression so that others don't get confused ;) – George Nov 17 '20 at 18:16
1

Sebastien, I think I understood the algorithm. I am not sure whether my solution is simpler but it is done with a single reduce. Give it a try:

%dw 2.0
output application/dw
var data = [5,5,4,4,4,2,2,1]
---

(data reduce (e, acc = {idx: 0, result: []}) -> do {
    var i = acc.idx + 1
    var last = if (isEmpty(acc.result)) {points: e, rank: 1} else acc.result[-1]
    ---
    {
        idx: i,
        result: acc.result + {points: e, rank: if (last.points == e) last.rank else i}
    }
}).result
George
  • 2,758
  • 12
  • 16
1

Assuming, my algorithm is correct, without using reduce,

%dw 2.0
output application/json
import * from dw::core::Arrays

var payload = [5,5,4,4,4,2,2,1]

fun getRank(inputArray, value) = 
using (rankArray = payload orderBy $ map $$ + 1)
rankArray[indexOf(inputArray, value)]
---

payload map (value) -> {
    "points" : value,
    "rank": getRank(payload, value)
}

What the function does is arrange the input array in descending order and save the index + 1 to set the ranking positions (rankArray). Then using the index of the first occurrence of the value from the original array, get the index from the rankArray and that would be the rank. This will result to

[
  {
    "points": 5,
    "rank": 1
  },
  {
    "points": 5,
    "rank": 1
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 4,
    "rank": 3
  },
  {
    "points": 2,
    "rank": 6
  },
  {
    "points": 2,
    "rank": 6
  },
  {
    "points": 1,
    "rank": 8
  }
]
oim
  • 1,141
  • 10
  • 14
0

Here is something working but I am creating a string to split it in elements:

%dw 2.0
output application/json
import * from dw::core::Strings

var points =[5,5,4,4,4,2,2,1]


var ranks = ((points reduce 
        (i,acc=[]) -> acc + 
                    (if (acc[-1] == null )  [i,true] 
                    else                    [i,acc[-1][0]-i !=0]))

    reduce (i, acc=[[0,1]]) -> acc + 
            (
                if (i[1]==true) [(acc[-1][1]+acc[-1][0]),1           ] 
                else            [acc[-1][0]             ,acc[-1][1]+1]
            ))[1 to -1]
    reduce (i,acc=[]) -> acc + i[0] 

---

(points zip ranks) map 
{
    points: $[0],
    rank:   $[1]
}