# 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.

- **Author:** Alex Martinez
- **Published:** May 9, 2023
- **Category:** Challenges
- **Tags:** MuleSoft, DataWeave
- **Source:** https://prostdev.com/post/dataweave-programming-challenge-6

---
## Series: DataWeave Programming Challenges (Part 6 of 8)

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

---

Try to solve this challenge on your own to maximize learning. We recommend you refer to the [DataWeave documentation](https://docs.mulesoft.com/dataweave/latest/) **only**. Try to avoid using Google or asking others so you can learn on your own and become a DataWeave expert!

> [!PLAYGROUND]
> [Solve on the Playground](https://dataweave.mulesoft.com/learn/playground?projectMethod=GHRepo&repo=alexandramartinez%2Fdataweave-challenges&path=challenges%2F6)

## Input

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

```
3
5
-6
300
```

## Explanation of the problem

- Create a [tail-recursive function](https://youtu.be/3UbTlLVNrVE) to get the [factorial](https://en.wikipedia.org/wiki/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

```dataweave
%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

**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): 

```dataweave
%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): 

```dataweave
%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. :)

```dataweave
%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): 

```dataweave
%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): 

```dataweave
%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.

```dataweave
%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

### 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.