Initial upload
This commit is contained in:
20
go/gross-store/.exercism/config.json
Normal file
20
go/gross-store/.exercism/config.json
Normal file
@@ -0,0 +1,20 @@
|
||||
{
|
||||
"blurb": "Learn about maps by selling items by the dozen at the Gross Store.",
|
||||
"authors": [
|
||||
"chocopowwwa"
|
||||
],
|
||||
"contributors": [
|
||||
"MiroslavGatsanoga"
|
||||
],
|
||||
"files": {
|
||||
"solution": [
|
||||
"gross_store.go"
|
||||
],
|
||||
"test": [
|
||||
"gross_store_test.go"
|
||||
],
|
||||
"exemplar": [
|
||||
".meta/exemplar.go"
|
||||
]
|
||||
}
|
||||
}
|
1
go/gross-store/.exercism/metadata.json
Normal file
1
go/gross-store/.exercism/metadata.json
Normal file
@@ -0,0 +1 @@
|
||||
{"track":"go","exercise":"gross-store","id":"7bfbc74502004cb3867b5bf345b7b1b0","url":"https://exercism.org/tracks/go/exercises/gross-store","handle":"halfdan","is_requester":true,"auto_approve":false}
|
40
go/gross-store/HELP.md
Normal file
40
go/gross-store/HELP.md
Normal file
@@ -0,0 +1,40 @@
|
||||
# Help
|
||||
|
||||
## Running the tests
|
||||
|
||||
To run the tests run the command `go test` from within the exercise directory.
|
||||
|
||||
If the test suite contains benchmarks, you can run these with the `--bench` and `--benchmem`
|
||||
flags:
|
||||
|
||||
go test -v --bench . --benchmem
|
||||
|
||||
Keep in mind that each reviewer will run benchmarks on a different machine, with
|
||||
different specs, so the results from these benchmark tests may vary.
|
||||
|
||||
## Submitting your solution
|
||||
|
||||
You can submit your solution using the `exercism submit gross_store.go` command.
|
||||
This command will upload your solution to the Exercism website and print the solution page's URL.
|
||||
|
||||
It's possible to submit an incomplete solution which allows you to:
|
||||
|
||||
- See how others have completed the exercise
|
||||
- Request help from a mentor
|
||||
|
||||
## Need to get help?
|
||||
|
||||
If you'd like help solving the exercise, check the following pages:
|
||||
|
||||
- The [Go track's documentation](https://exercism.org/docs/tracks/go)
|
||||
- [Exercism's support channel on gitter](https://gitter.im/exercism/support)
|
||||
- The [Frequently Asked Questions](https://exercism.org/docs/using/faqs)
|
||||
|
||||
Should those resources not suffice, you could submit your (incomplete) solution to request mentoring.
|
||||
|
||||
To get help if you're having trouble, you can use one of the following resources:
|
||||
|
||||
- [How to Write Go Code](https://golang.org/doc/code.html)
|
||||
- [Effective Go](https://golang.org/doc/effective_go.html)
|
||||
- [Go Resources](http://golang.org/help)
|
||||
- [StackOverflow](http://stackoverflow.com/questions/tagged/go)
|
31
go/gross-store/HINTS.md
Normal file
31
go/gross-store/HINTS.md
Normal file
@@ -0,0 +1,31 @@
|
||||
# Hints
|
||||
|
||||
## General
|
||||
|
||||
- [Go by example map][gobyexample-map]
|
||||
- [Go maps in action][goblog-map]
|
||||
|
||||
## 1. Store the unit of measurement in your program
|
||||
|
||||
- To store the measurement in your program, you can use map literal, see [go blog about map][goblog-map]
|
||||
|
||||
## 2. Create a new bill
|
||||
|
||||
- To create a new bill, you all you need to do is reinitialize the customer, see [go blog about map][goblog-map]
|
||||
|
||||
## 3. Add item to the customer bill
|
||||
|
||||
- To check whether the given unit of measurement is correct, you can test your measurement map for a key without retrieving a value, see [go blog about map][goblog-map]
|
||||
|
||||
## 4. Remove item from the customer bill
|
||||
|
||||
- To check whether the given item is in customer bill, you can test your measurement map for a key without retrieving a value, see [go blog about map][goblog-map]
|
||||
|
||||
- To check whether the given unit of measurement is correct, you can test your measurement map for a key without retrieving a value, see [go blog about map][goblog-map]
|
||||
|
||||
## 5. Return the number of specific item that is in the customer bill
|
||||
|
||||
- To check whether the given item is in customer bill, you can test your measurement map for a key without retrieving a value, see [go blog about map][goblog-map]
|
||||
|
||||
[gobyexample-map]: https://gobyexample.com/maps
|
||||
[goblog-map]: https://blog.golang.org/maps
|
159
go/gross-store/README.md
Normal file
159
go/gross-store/README.md
Normal file
@@ -0,0 +1,159 @@
|
||||
# Gross Store
|
||||
|
||||
Welcome to Gross Store on Exercism's Go Track.
|
||||
If you need help running the tests or submitting your code, check out `HELP.md`.
|
||||
If you get stuck on the exercise, check out `HINTS.md`, but try and solve it without using those first :)
|
||||
|
||||
## Introduction
|
||||
|
||||
In go, `map` is a built-in data type that maps keys to values. In other programming language, you might be familiar with the concept of `map` as a dictionary, hash table, key/value store or an associative array.
|
||||
|
||||
Syntactically, `map` looks like this:
|
||||
|
||||
```go
|
||||
map[KeyType]ElementType
|
||||
```
|
||||
|
||||
It is also important to know that each key is unique, meaning that assigning the same key twice will overwrite the value of the corresponding key.
|
||||
|
||||
To create a map, you can do:
|
||||
|
||||
```go
|
||||
// With map literal
|
||||
foo := map[string]int{}
|
||||
```
|
||||
|
||||
or
|
||||
|
||||
```go
|
||||
// or with make function
|
||||
foo := make(map[string]int)
|
||||
```
|
||||
|
||||
Here are some operations that you can do with a map
|
||||
|
||||
```go
|
||||
// Add a value in a map with the `=` operator:
|
||||
foo["bar"] = 42
|
||||
// Here we update the element of `bar`
|
||||
foo["bar"] = 73
|
||||
// To retrieve a map value, you can use
|
||||
baz := foo["bar"]
|
||||
// To delete an item from a map, you can use
|
||||
delete(foo, "bar")
|
||||
```
|
||||
|
||||
If you try to retrieve the value for a key which does not exist in the map, it will return the zero value of the value type.
|
||||
This can confuse you, especially if the default value of your `ElementType` (for example, 0 for an int), is a valid value.
|
||||
To check whether a key exists in your map, you can use
|
||||
|
||||
```go
|
||||
value, exists := foo["baz"]
|
||||
// If the key "baz" does not exist,
|
||||
// value: 0; exists: false
|
||||
```
|
||||
|
||||
## Instructions
|
||||
|
||||
A friend of yours has an old wholesale store called **Gross Store**.
|
||||
The name comes from the quantity of the item that the store sell: it's all in [gross unit][gross-unit].
|
||||
Your friend asked you to implement a point of sale (POS) system for his store.
|
||||
**First, you want to build a prototype for it.**
|
||||
**In your prototype, your system will only record the quantity.**
|
||||
Your friend gave you a list of measurements to help you:
|
||||
|
||||
| Unit | Score |
|
||||
| ------------------ | ----- |
|
||||
| quarter_of_a_dozen | 3 |
|
||||
| half_of_a_dozen | 6 |
|
||||
| dozen | 12 |
|
||||
| small_gross | 120 |
|
||||
| gross | 144 |
|
||||
| great_gross | 1728 |
|
||||
|
||||
## 1. Store the unit of measurement in your program
|
||||
|
||||
In order to use the measurement, you need to store the measurement in your program.
|
||||
|
||||
```go
|
||||
units := Units()
|
||||
fmt.Println(units)
|
||||
// Output: map[...] with entries like ("dozen": 12)
|
||||
```
|
||||
|
||||
## 2. Create a new customer bill
|
||||
|
||||
You need to implement a function that create a new (empty) bill for the customer.
|
||||
|
||||
```go
|
||||
bill := NewBill()
|
||||
fmt.Println(bill)
|
||||
// Output: map[]
|
||||
```
|
||||
|
||||
## 3. Add an item to the customer bill
|
||||
|
||||
To implement this, you'll need to:
|
||||
|
||||
- Return `false` if the given `unit` is not in the `units` map.
|
||||
- Otherwise add the item to the customer `bill`, indexed by the item name, then return `true`.
|
||||
|
||||
```go
|
||||
bill := NewBill()
|
||||
units := Units()
|
||||
ok := AddItem(bill, units, "carrot", "dozen")
|
||||
fmt.Println(ok)
|
||||
// Output: true (since dozen is a valid unit)
|
||||
```
|
||||
|
||||
> Note that the returned value is type `bool`.
|
||||
|
||||
## 4. Remove an item from the customer bill
|
||||
|
||||
To implement this, you'll need to:
|
||||
|
||||
- Return `false` if the given item is **not** in the bill
|
||||
- Return `false` if the given `unit` is not in the `units` map.
|
||||
- Return `false` if the new quantity would be less than 0.
|
||||
- If the new quantity is 0, completely remove the item from the `bill` then return `true`.
|
||||
- Otherwise, reduce the quantity of the item and return `true`.
|
||||
|
||||
```go
|
||||
bill := NewBill()
|
||||
units := Units()
|
||||
ok := RemoveItem(bill, units, "carrot", "dozen")
|
||||
fmt.Println(ok)
|
||||
// Output: false (because there are no carrots in the bill)
|
||||
```
|
||||
|
||||
> Note that the returned value is type `bool`.
|
||||
|
||||
## 5. Return the quantity of a specific item that is in the customer bill
|
||||
|
||||
To implement this, you'll need to:
|
||||
|
||||
- Return `0` and `false` if the `item` is not in the bill.
|
||||
- Otherwise, return the quantity of the item in the `bill` and `true`.
|
||||
|
||||
```go
|
||||
bill := map[string]int{"carrot", 12, "grapes", 3}
|
||||
qty, ok := GetItem(bill, "carrot")
|
||||
fmt.Println(qty)
|
||||
// Output: 12
|
||||
fmt.Println(ok)
|
||||
// Output: true
|
||||
```
|
||||
|
||||
> Note that the returned value are types `int` and `bool`.
|
||||
|
||||
[gross-unit]: https://en.wikipedia.org/wiki/Gross_(unit)
|
||||
|
||||
## Source
|
||||
|
||||
### Created by
|
||||
|
||||
- @chocopowwwa
|
||||
|
||||
### Contributed to by
|
||||
|
||||
- @MiroslavGatsanoga
|
3
go/gross-store/go.mod
Normal file
3
go/gross-store/go.mod
Normal file
@@ -0,0 +1,3 @@
|
||||
module gross
|
||||
|
||||
go 1.16
|
59
go/gross-store/gross_store.go
Normal file
59
go/gross-store/gross_store.go
Normal file
@@ -0,0 +1,59 @@
|
||||
package gross
|
||||
|
||||
// Units stores the Gross Store unit measurements.
|
||||
func Units() map[string]int {
|
||||
return map[string]int{
|
||||
"quarter_of_a_dozen": 3,
|
||||
"half_of_a_dozen": 6,
|
||||
"dozen": 12,
|
||||
"small_gross": 120,
|
||||
"gross": 144,
|
||||
"great_gross": 1728,
|
||||
}
|
||||
}
|
||||
|
||||
// NewBill creates a new bill.
|
||||
func NewBill() map[string]int {
|
||||
return map[string]int{}
|
||||
}
|
||||
|
||||
// AddItem adds an item to customer bill.
|
||||
func AddItem(bill, units map[string]int, item, unit string) bool {
|
||||
val, exists := units[unit]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
bill[item] += val
|
||||
return true
|
||||
}
|
||||
|
||||
// RemoveItem removes an item from customer bill.
|
||||
func RemoveItem(bill, units map[string]int, item, unit string) bool {
|
||||
qty, exists := bill[item]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
val, exists := units[unit]
|
||||
if !exists {
|
||||
return false
|
||||
}
|
||||
|
||||
if qty - val < 0 {
|
||||
return false
|
||||
}
|
||||
|
||||
if qty - val == 0 {
|
||||
delete(bill, item)
|
||||
} else {
|
||||
bill[item] -= val
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// GetItem returns the quantity of an item that the customer has in his/her bill.
|
||||
func GetItem(bill map[string]int, item string) (int, bool) {
|
||||
qty, exists := bill[item]
|
||||
return qty, exists
|
||||
}
|
255
go/gross-store/gross_store_test.go
Normal file
255
go/gross-store/gross_store_test.go
Normal file
@@ -0,0 +1,255 @@
|
||||
package gross
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
type entry struct {
|
||||
name string
|
||||
unit string
|
||||
qty int
|
||||
}
|
||||
|
||||
func TestUnits(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
qty int
|
||||
}{
|
||||
{"quarter_of_a_dozen", 3},
|
||||
{"half_of_a_dozen", 6},
|
||||
{"dozen", 12},
|
||||
{"small_gross", 120},
|
||||
{"gross", 144},
|
||||
{"great_gross", 1728},
|
||||
}
|
||||
|
||||
units := Units()
|
||||
for _, tt := range tests {
|
||||
qty, ok := units[tt.name]
|
||||
|
||||
if !ok {
|
||||
t.Errorf(`Unit "%s" not found!`, tt.name)
|
||||
continue
|
||||
}
|
||||
|
||||
if qty != tt.qty {
|
||||
t.Errorf(`Unit "%s" should have quantity %d, found %d`, tt.name, tt.qty, qty)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
func TestAddItem(t *testing.T) {
|
||||
tests := []struct {
|
||||
name string
|
||||
entry []entry
|
||||
expected bool
|
||||
}{
|
||||
{
|
||||
"Invalid measurement unit",
|
||||
[]entry{
|
||||
{"pasta", "", 0},
|
||||
{"onion", "quarter", 0},
|
||||
{"pasta", "pound", 0},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{
|
||||
"Valid measurement unit",
|
||||
[]entry{
|
||||
{"peas", "quarter_of_a_dozen", 3},
|
||||
{"tomato", "half_of_a_dozen", 6},
|
||||
{"chili", "dozen", 12},
|
||||
{"cucumber", "small_gross", 120},
|
||||
{"potato", "gross", 144},
|
||||
{"zucchini", "great_gross", 1728},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{
|
||||
"check quantity of item added twice",
|
||||
[]entry{
|
||||
{"peas", "quarter_of_a_dozen", 3},
|
||||
{"peas", "quarter_of_a_dozen", 6},
|
||||
{"tomato", "half_of_a_dozen", 6},
|
||||
{"tomato", "quarter_of_a_dozen", 9},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
units := Units()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bill := NewBill()
|
||||
for _, item := range tt.entry {
|
||||
ok := AddItem(bill, units, item.name, item.unit)
|
||||
if ok != tt.expected {
|
||||
t.Errorf("Expected %t from AddItem, found %t at %v", tt.expected, ok, item.name)
|
||||
}
|
||||
|
||||
itemQty, ok := bill[item.name]
|
||||
if ok != tt.expected {
|
||||
t.Errorf("Could not find item %s in customer bill", item.name)
|
||||
}
|
||||
|
||||
if itemQty != item.qty {
|
||||
t.Errorf("Expected %s to have quantity %d in customer bill, found %d", item.name, item.qty, itemQty)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveItem(t *testing.T) {
|
||||
type expectedItem struct {
|
||||
name string
|
||||
unit string
|
||||
qty int
|
||||
exists bool
|
||||
}
|
||||
|
||||
tests := []struct {
|
||||
name string
|
||||
remove []expectedItem
|
||||
expected bool
|
||||
}{
|
||||
{"Item Not found in bill",
|
||||
[]expectedItem{
|
||||
{"papaya", "gross", 0, false},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{"Invalid measurement unit",
|
||||
[]expectedItem{
|
||||
{"peas", "pound", 3, true},
|
||||
{"tomato", "kilogram", 6, true},
|
||||
{"cucumber", "stone", 120, true},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{"Resulted qty less than 0",
|
||||
[]expectedItem{
|
||||
{"peas", "half_of_a_dozen", 3, true},
|
||||
{"tomato", "dozen", 6, true},
|
||||
{"chili", "small_gross", 12, true},
|
||||
{"cucumber", "gross", 120, true},
|
||||
{"potato", "great_gross", 144, true},
|
||||
},
|
||||
false,
|
||||
},
|
||||
{"Should delete the item if 0",
|
||||
[]expectedItem{
|
||||
{"peas", "quarter_of_a_dozen", 0, false},
|
||||
{"tomato", "half_of_a_dozen", 0, false},
|
||||
{"chili", "dozen", 0, false},
|
||||
{"cucumber", "small_gross", 0, false},
|
||||
{"potato", "gross", 0, false},
|
||||
{"zucchini", "great_gross", 0, false},
|
||||
},
|
||||
true,
|
||||
},
|
||||
{"Should reduce the qty",
|
||||
[]expectedItem{
|
||||
{"chili", "half_of_a_dozen", 6, true},
|
||||
{"cucumber", "dozen", 108, true},
|
||||
{"zucchini", "gross", 1584, true},
|
||||
},
|
||||
true,
|
||||
},
|
||||
}
|
||||
|
||||
units := Units()
|
||||
for _, tt := range tests {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bill := setupInitialBillData()
|
||||
for _, item := range tt.remove {
|
||||
ok := RemoveItem(bill, units, item.name, item.unit)
|
||||
if ok != tt.expected {
|
||||
t.Errorf("Expected %t from RemoveItem, found %t at %v", tt.expected, ok, item.name)
|
||||
}
|
||||
|
||||
itemQty, ok := bill[item.name]
|
||||
if ok != item.exists {
|
||||
t.Errorf("Could not find item %s in customer bill", item.name)
|
||||
}
|
||||
if itemQty != item.qty {
|
||||
t.Errorf("Expected %s to have quantity %d in customer bill, found %d", item.name, item.qty, itemQty)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestNewBill(t *testing.T) {
|
||||
// Success, zero out the bill
|
||||
t.Run("Should reset customerbill", func(t *testing.T) {
|
||||
bill := NewBill()
|
||||
|
||||
if len(bill) != 0 {
|
||||
t.Error("Customer bill must be empty")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
func TestGetItem(t *testing.T) {
|
||||
type expectedItem struct {
|
||||
name string
|
||||
expected bool
|
||||
qty int
|
||||
}
|
||||
|
||||
test := []struct {
|
||||
name string
|
||||
getItem []expectedItem
|
||||
}{
|
||||
{
|
||||
"Item Not found in bill",
|
||||
[]expectedItem{
|
||||
{"grape", false, 0},
|
||||
},
|
||||
},
|
||||
{
|
||||
"Success",
|
||||
[]expectedItem{
|
||||
{"peas", true, 3},
|
||||
{"tomato", true, 6},
|
||||
{"chili", true, 12},
|
||||
{"cucumber", true, 120},
|
||||
{"potato", true, 144},
|
||||
{"zucchini", true, 1728},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for _, tt := range test {
|
||||
t.Run(tt.name, func(t *testing.T) {
|
||||
bill := setupInitialBillData()
|
||||
for _, item := range tt.getItem {
|
||||
itemQty, ok := GetItem(bill, item.name)
|
||||
|
||||
if ok != item.expected {
|
||||
msg := "Could not find item %s in customer bill, expected %t"
|
||||
if item.expected == false {
|
||||
msg = "Found item %s in customer bill, expected %t"
|
||||
}
|
||||
|
||||
t.Errorf(msg, item.name, item.expected)
|
||||
}
|
||||
|
||||
if itemQty != item.qty {
|
||||
t.Errorf("Expected %s to have quantity %d in customer bill, found %d", item.name, item.qty, itemQty)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func setupInitialBillData() map[string]int {
|
||||
bill := NewBill()
|
||||
bill["peas"] = 3
|
||||
bill["tomato"] = 6
|
||||
bill["chili"] = 12
|
||||
bill["cucumber"] = 120
|
||||
bill["potato"] = 144
|
||||
bill["zucchini"] = 1728
|
||||
return bill
|
||||
}
|
Reference in New Issue
Block a user