2
votes

Dataweave: créer un classement à partir des scores

Avec l'entrée suivante:

[
  {
    "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
  }
]

Je souhaite générer la sortie suivante:

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

J'ai trouvé une solution (voir la réponse) mais je me demande s'il existe une meilleure façon de le faire.


1 commentaires

Salut Sébastien, pourriez-vous s'il vous plaît expliquer l'algorithme en anglais sur la façon dont un rang est calculé?


4 Réponses :


0
votes

Voici quelque chose qui fonctionne mais je crée une chaîne pour la diviser en éléments:

%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]
}


0 commentaires

1
votes

Sébastien, je pense avoir compris l'algorithme. Je ne sais pas si ma solution est plus simple mais elle se fait avec une seule reduce . Essaie:

%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


1 commentaires

D'accord! C'est actuellement non programmé!



1
votes

En supposant que mon algorithme est correct, sans utiliser de réduction,

[
  {
    "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
  }
]

Ce que fait la fonction est d'organiser le tableau d'entrée dans l'ordre décroissant et d'enregistrer l'index + 1 pour définir les positions de classement (rankArray). Ensuite, en utilisant l'index de la première occurrence de la valeur du tableau d'origine, obtenez l'index du rankArray et ce serait le rang. Cela se traduira par

%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)
}


1 commentaires

vertigineux et correct



5
votes

Je ne sais pas si cela couvre tous vos cas de test, mais voici une version plus courte du code que j'ai trouvée -

%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
}

S'il vous plait, faite moi part de votre avis.


3 commentaires

Bien fait, mettez maintenant un espace entre la map et l'expression lambda pour que les autres ne soient pas confus;)


done.thanks @George :)


J'adore cette version !!! Bien joué.