ProstDev ProstDev
Challenges May 9, 2023 · 2 min read

DataWeave programming challenge #6: Using tail-recursion to get the factorial of a number

Create a tail-recursive function to get the factorial of each positive number from the payload.

By Alex Martinez
Thumbnail: DataWeave programming challenge #6: Using tail-recursion to get the factorial of a number Read & copy the full video transcript

Try to solve this challenge on your own to maximize learning. We recommend you refer to the DataWeave documentation only. Try to avoid using Google or asking others so you can learn on your own and become a DataWeave expert!

Solve on the Playground

Input

Consider the following input payload (can be of txt format):

3
5
-6
300

Explanation of the problem

  • Create a tail-recursive function to get the factorial of each positive number from the payload.
  • Sum the results.
  • Retrieve the digits/characters located at positions 20-25.
  • Make sure to return a number and not a string.
  • Numbers 0 or less won’t be calculated.

For example:

  • The factorial of 3 is 6 (3 x 2 x 1)
  • The factorial of 5 is 120 (5 x 4 x 3 x 2 x 1)
  • The factorial of -6 won’t be calculated so the result will be 0
  • And so on
  • Once the results are summed (6 + 120 + 0…), extract the digits at indexes 20 to 25.
  • Return this last 6-digit number.

Expected output

In this case, the expected output would be:

537046

Clues

If you’re stuck with your solution, feel free to check out some of these clues to give you ideas on how to solve it!

Clue #1

Use lines() from the Strings module or splitBy() to process every line.

Clue #2

Make sure to use tail-recursiveness and not regular recursiveness. Otherwise, your script might not work.

Clue #3

Make sure to create an if statement before calling the function in recursion. Otherwise, you might get stuck in an infinite loop!

Clue #4

You can use the keyword as to transform to/from strings and numbers.

Clue #5

You can extract characters from a string with the range selector [ x to y ]

Answer

If you haven’t solved this challenge yet, we encourage you to keep trying! It’s ok if it’s taking longer than you thought. We all have to start somewhere ✨ Check out the clues and read the docs before giving up. You got this!! 💙

There are many ways to solve this challenge, but you can find here one of my solutions!

Solution #1

%dw 2.0
import lines from dw::core::Strings
output application/json
fun factorial(num:Number, result:Number=1):Number = do {
	if (num == 0) result
	else if (num < 0) 0
	else factorial(num - 1, result * num)
}
---
lines(payload) map factorial($)
then sum($) as String 
then $[20 to 25] as Number

Subscribe to receive notifications as soon as new content is published ✨

Reader notes

Helpful comments preserved from the original post.

  • Nicky van Steensel van der Aa · Jul 18, 2023

    For those using dw::core::Arrays slice it excludes the last index, so select 20-26

  • Nicky van Steensel van der Aa · Jul 18, 2023
    %dw 2.0
    output application/json
    
    fun solve(x)=
    x reduce (item, acc) -> ( (if(item > 0) acc + factorial(item) else acc))
    
    fun factorial(x)=
    2 to x reduce (item, acc) -> (acc*item)
    
    ---
    
    (solve(payload splitBy('\n')) splitBy(''))[20 to 25] joinBy("")
  • Nirmala Vairaganthan · May 10, 2023
    %dw 2.0
    fun factorial(num)= num to 1 reduce ((item, accumulator) -> accumulator * item)
    fun pos(val) = val[20 to 25]
    ---
    pos(sum((payload splitBy "\n" ) map factorial($))) as Number
  • Disha Bhar · May 10, 2023

    Tried this out. :)

    %dw 2.0
    import * from dw::core::Strings
    fun tailFactorial(n:Number, p:Number = 1) =
        (if(n == 1 or n == 0)
            p
        else
            tailFactorial(n-1, (p * n)))
    output application/json
    ---
    (sum((payload splitBy "\n") filter($>0) map tailFactorial($ as Number) )as String)[20 to 25] as Number
  • Felix Schnabel · May 9, 2023
    %dw 2.0
    output application/json
    import * from dw::core::Strings
    @TailRec
    fun solve(i: Number, acc: Number = 1): Number = i match {
        case 0 -> acc
        case i if(i < 0) -> 0
        else -> solve(i - 1, acc * i)
    }
    ---
    lines(payload)
        map solve($ as Number)
        then sum($)
        then $[20 to 25] as Number
  • Sudiptaa · May 9, 2023
    %dw 2.0
    output application/json
    
    import lines from dw::core::Strings
    
    fun factorial(n:Number,res:Number=1):Number = if (n == 1 or n ==0) res
    
        else if (n < 0) 0
    
        else factorial(n - 1,res * n)
    ---
    
    sum(lines(payload) map factorial($))[20 to 25] as Number
  • Shyam Raj Prasad · May 9, 2023

    Solved using reduce.

    %dw 2.0
    import lines from dw::core::Strings
    output application/json
    fun factorial(x) = 1 to x reduce ((item, accumulator) -> 
        accumulator * item
    )
    
    ---
    ((lines(payload) filter ($>0) reduce ((item, accumulator) ->
        factorial(item) + accumulator
     )) as String)[20 to 25] as Number

FAQs

Frequently asked questions about this post.

  • What is this DataWeave challenge asking me to do?

    The challenge asks you to create a tail-recursive function that gets the factorial of each positive number in the payload, sum the results, then retrieve the digits located at positions 20 to 25, returning a number and not a string. Numbers that are 0 or less aren't calculated, so for the sample input the factorial of 3 is 6, the factorial of 5 is 120, the factorial of -6 isn't calculated (treated as 0), and the expected output is 537046.

  • How do I process every line of the input payload?

    As the clues suggest, you can use lines() from the Strings module or splitBy() to process every line of the payload, which can be in txt format.

  • Why does the post insist on tail-recursion instead of regular recursion?

    The clues warn that you must use tail-recursiveness and not regular recursiveness, otherwise your script might not work.

  • How do I avoid an infinite loop in the recursive factorial function?

    Make sure to create an if statement before calling the function in recursion; otherwise you might get stuck in an infinite loop, as noted in the clues.

  • How do I return a number instead of a string for the final result?

    You can use the keyword as to transform to and from strings and numbers, and you extract the characters at positions 20 to 25 from a string using the range selector [ x to y ] before converting the result back to a number.

  • Where should I look for help while solving this challenge?

    The post recommends referring only to the DataWeave documentation at https://docs.mulesoft.com/dataweave/latest/ and avoiding Google or asking others, so you can learn on your own; you can also solve it directly on the linked DataWeave Playground.

More from this series

DataWeave Programming Challenges· Part 6 of 8
  1. 1.DataWeave programming challenge #1: Add numbers separated by paragraphs and get the max number
  2. 2.DataWeave programming challenge #2: Rock Paper Scissors game score system
  3. 3.DataWeave programming challenge #3: Count palindrome phrases using the Strings module
  4. 4.DataWeave programming challenge #4: Solve the Tower of Hanoi mathematical puzzle
  5. 5.DataWeave programming challenge #5: Reverse a phrase's words, but keep the punctuation
  6. 6.DataWeave programming challenge #6: Using tail-recursion to get the factorial of a number
  7. 7.DataWeave programming challenge #7: Modify certain values from a JSON structure
  8. 8.DataWeave programming challenge #8: Sum all digits to get a 1-digit number
Search

Loading search…