dev.to staff

Posted on

# Daily Challenge #74 - Free Pizza

In an attempt to boost sales, the manager of the pizzeria you work at has devised a new pizza rewards system. Although, he isn't exactly sure what he wants the variables to be. The rewards system may change in the future. Your manager wants you to implement a function that, given a dictionary of customers, a minimum number of orders, and a minimum order value, returns a set of the customers who are eligible for a reward.

Customers in the dictionary are represented as:
`{ 'customerName' : [list_of_order_values_as_integers] }`

Test 1:
Make at least 5 orders of at least 20\$ each and get a free pizza!

```min_orders = 5
min_price = 20
customers = {
'John Doe' : [22, 30, 11, 17, 15, 52, 27, 12],
'Jane Doe' : [5, 17, 30, 33, 40, 22, 26, 10, 11, 45]
}
```

Test 2:
Make at least 2 orders of at least 50\$ each and get a free pizza!

```min_orders = 2
min_price = 50
customers = {
'Joey Bonzo' : [22, 67, 53, 29],
'Jennifer Bonzo' : [51, 19]
}
```

Test 3:
Make at least 3 orders of at least 15\$ each and get a free pizza!

```min_orders = 3
min_price = 15
customers = {
'Natsumi Sakamoto' : [15, 15, 14],
'Gorou Hironaka' : [15, 15, 15],
'Shinju Tanabe' : [120, 240]
}
```

This challenge comes from kingcobra on CodeWars. Thank you to CodeWars, who has licensed redistribution of this challenge under the 2-Clause BSD License!

Want to propose a challenge idea for a future post? Email yo+challenge@dev.to with your suggestions!

Amin • Edited

Elm

``````module FreePizza exposing (Customer, freePizza)

type alias Customer =
{ name : String
, purchases : List Int
}

isEligible : Int -> Int -> Customer -> Bool
isEligible minimumOrders minimumPrice =
.purchases
>> List.filter ((<=) minimumPrice)
>> List.length
>> (<=) minimumOrders

freePizza : Int -> Int -> List Customer -> List Customer
freePizza minimumOrders minimumPrice =
List.filter <| isEligible minimumOrders minimumPrice

``````

Explainations

``````module FreePizza exposing (Customer, freePizza)
``````

This will define anything that we choose to export to the outside world importing our module. In this case, we only want to expose our `Customer` type alias & `freePizza` function for our tests (see below).

``````type alias Customer =
{ name : String
, purchases : List Int
}
``````

This will define a customer in our application. Note that I choosed to use a `name` field for the name of the customer and a `purchases` field for the total record of the customer's purchases.

``````isEligible : Int -> Int -> Customer -> Bool
isEligible minimumOrders minimumPrice =
.purchases
>> List.filter ((<=) minimumPrice)
>> List.length
>> (<=) minimumOrders
``````

This will define the inner logic of the challenge. Basically what it does is:

1. Grab the purchases out of the current iterated object (customer). Almost anything in Elm is a function, so is `.purchases` which is a function that accepts a customer and returns a list of integers (the purchases). `.purchases : Customer -> List Int`. It is equivalent to this in JavaScript: `const { purchases } = customer;`.
2. Filter out all the customer's purchases that are not above or equal to the minimum order's price defined by our free pizza's policy. The `((<=) minimumPrice)` part is equivalent to `(\purchase -> purchase >= minimumPrice)`
3. Calculate the length of the filtered list.
4. Check whether the length of the list is at least equal or above the minimum orders, which means that it will return true when the customer has made enough purchases.
``````freePizza : Int -> Int -> List Customer -> List Customer
freePizza minimumOrders minimumPrice =
List.filter <| isEligible minimumOrders minimumPrice
``````

This will filter out all the customer that are non-eligible to our current free pizza's policy.

Tests

``````module FreePizzaTest exposing (suite)

import Expect exposing (equal)
import FreePizza exposing (Customer, freePizza)
import Test exposing (Test, describe, test)

suite : Test
suite =
describe "Free Pizza"
[ test "it should return a set of customers who are eligible for a reward #1" <|
\_ ->
let
minimumOrders : Int
minimumOrders =
5

minimumPrice : Int
minimumPrice =
20

customers : List Customer
customers =
[ { name = "John Doe"
, purchases = [ 22, 30, 11, 17, 15, 52, 27, 12 ]
}
, { name = "Jane Doe"
, purchases = [ 5, 17, 30, 33, 40, 22, 26, 10, 11, 45 ]
}
]

expectations : List Customer
expectations =
[ { name = "Jane Doe"
, purchases = [ 5, 17, 30, 33, 40, 22, 26, 10, 11, 45 ]
}
]
in
equal expectations <| freePizza minimumOrders minimumPrice customers
, test "it should return a set of customers who are eligible for a reward #2" <|
\_ ->
let
minimumOrders : Int
minimumOrders =
2

minimumPrice : Int
minimumPrice =
50

customers : List Customer
customers =
[ { name = "Joey Bonzo"
, purchases = [ 22, 67, 53, 29 ]
}
, { name = "Jennifer Bonzo"
, purchases = [ 51, 19 ]
}
]

expectations : List Customer
expectations =
[ { name = "Joey Bonzo"
, purchases = [ 22, 67, 53, 29 ]
}
]
in
equal expectations <| freePizza minimumOrders minimumPrice customers
, test "it should return a set of customers who are eligible for a reward #3" <|
\_ ->
let
minimumOrders : Int
minimumOrders =
3

minimumPrice : Int
minimumPrice =
15

customers : List Customer
customers =
[ { name = "Natsumi Sakamoto"
, purchases = [ 15, 15, 14 ]
}
, { name = "Gorou Hironaka"
, purchases = [ 15, 15, 15 ]
}
, { name = "Shinju Tanabe"
, purchases = [ 120, 240 ]
}
]

expectations : List Customer
expectations =
[ { name = "Gorou Hironaka"
, purchases = [ 15, 15, 15 ]
}
]
in
equal expectations <| freePizza minimumOrders minimumPrice customers
]
``````

Playground

Test it online here.

Javascript

``````function promo(order, price, customers) {
return Object.keys(customers).filter(c => customers[c].filter(p => p >= price).length >= order);
}

// Test 1
promo(min_orders, min_price, customers)
// ["Jane Doe"]

// Test 2
promo(min_orders, min_price, customers)
// ["Joey Bonzo"]

// Test 3
promo(min_orders, min_price, customers)
// ["Gorou Hironaka"]
``````

Oleksii Filonenko

Elixir:

``````defmodule Day74 do
def eligible(customers, min_orders, min_price) do
for customer = {_, orders} <- customers,
Enum.count(orders, &(&1 >= min_price)) >= min_orders,
into: %{},
do: customer
end
end
``````

Tests:

``````defmodule Day74Test do
use ExUnit.Case

test "5 of \$20" do
customers = %{
"John Doe" => [22, 30, 11, 17, 15, 52, 27, 12],
"Jane Doe" => [5, 17, 30, 33, 40, 22, 26, 10, 11, 45]
}

assert %{"Jane Doe" => _} = Day74.eligible(customers, 5, 20)
end

test "2 of \$50" do
customers = %{
"Joey Bonzo" => [22, 67, 53, 29],
"Jennifer Bonzo" => [51, 19]
}

assert %{"Joey Bonzo" => _} = Day74.eligible(customers, 2, 50)
end

test "3 of \$15" do
customers = %{
"Natsumi Sakamoto" => [15, 15, 14],
"Gorou Hironaka" => [15, 15, 15],
"Shinju Tanabe" => [120, 240]
}

assert %{"Gorou Hironaka" => _} = Day74.eligible(customers, 3, 15)
end
end
``````

willsmart

Here's one in TypeScript

My preferred way of passing bags of arguments to functions in JS is by destructuring an object, which gets around the whole lets-just-remember-the-second-argument-was-minOrders thing.

The hacky embedded test harness is just there to make this portable.

hmm, I think I found a bug in the codepen plugin, where the template string at the bottom is being styled like it never got closed.
Will find the repo and pop in a bug report.

K.V.Harish

My solution in js

``````const rewardsSystem = (minOrders = 0, minPrice = 0, customers = {}) => Object.keys(customers).filter((customer) => customers[customer].filter((value) => value >= minPrice).length >= minOrders);
``````

LordApple

c++, hope it's correct.

``````#include <iostream>
#include <unordered_set>
#include <utility>
#include <vector>

struct Customer{
Customer(std::string t_name, std::vector<int> t_orders) : name(std::move(t_name)), orders(std::move(t_orders)){
};

std::string name;
std::vector<int> orders;
};

auto freePizza(const std::vector<Customer>& customers, const int& minPrice, const int& minOrders){
std::vector<Customer> returnValue{};

for(const auto& customer : customers){
if(customer.orders.size() < minOrders)
continue;

int count = 0;

for(const auto& item : customer.orders){
if(item >= minPrice)
++count;
}

if(count >= minOrders)
returnValue.push_back(customer);
}
return returnValue;
}
``````

dillan teagle

Python solution

``````def rewarder(customers, orders, price):
eligible = set()
for key, value in customers.items():
number_of_occurences = sum(num > price for num in value)
if number_of_occurences >= orders:

return eligible

x = rewarder(customers, min_orders, min_price)
print(x)
``````

Michael Baas

### APL - Solution 1 (using Dyalog APL)

I'm passing the argument in a suitable array-format for convenience and brevity:

```promo←{(⊂'')~⍨(⊂⍵){(⍺[1]≤+/⍺[2]≤2⊃⍵)/1⊃⍵}¨3⊃⍵}
```

#### Output:

```      promo 5 20(('John Doe'(22 30 11 17 15 15 52 27 12))('Jane Doe'(5 17 30 33 40 22 26 10 11 45)))
┌────────┐
│Jane Doe│
└────────┘
promo 2 50 (('Joey Bonzo'(22 67 53 29))('Jennifer Bonzo'(51 19)))
┌──────────┐
│Joey Bonzo│
└──────────┘
promo 3 15 (('Natsumi Sakamoto'(15 15 14))('Gorou Hironaka'(15 15 15))('Shinju Tanabe'(120 40)))
┌──────────────┐
│Gorou Hironaka│
└──────────────┘

```

### APL - Solution 2

Since the task was shown with JSON-Data, I want to also show how to tackle this with JSON-Data in APL.

```promo2←{(⊂'')~⍨(⊂⍵.(min_orders min_price)){(⍺[1]≤+/⍺[2]≤⍵.hist)/⍵.id}¨⍵.customers}
```

#### Testing

```      Test1←⎕JSON'{"min_orders":5,"min_price":20,"customers":[{"id":"John Doe","hist":[22, 30, 11 ,17 ,15 ,52, 27 ,12]},{"id":"Jane Doe","hist":[5 ,17 ,30 ,33, 40, 22, 26, 10, 11 ,45]}]}'
promo2 Test1
┌────────┐
│Jane Doe│
└────────┘

Test2←⎕JSON'{"min_orders":2,"min_price":50,"customers":[{"id":"Joey Bonzo","hist":[22,67,53,29]},{"id":"Jennifer Bonzo","hist": [51,19]}]}'
promo2 Test2
┌──────────┐
│Joey Bonzo│
└──────────┘

Test3←⎕JSON'{"min_orders":3,"min_price":15,"customers":[{"id":"Natsumi Sakamoto","hist":[15,15,14]},{"id":"Gorou Hironaka","hist": [15,15,15]},{"id":"Shinju Tanabe","hist":[120,40]}]}'
promo2 Test3
┌──────────────┐
│Gorou Hironaka│
└──────────────┘
```

Feel free to experiment and Try it online! ;)