2017-08-15

This commit is contained in:
Brian Buller 2017-08-15 09:55:28 -05:00
parent 549ba5084e
commit 4a9b690bb2
28 changed files with 1153 additions and 18 deletions

53
go/accumulate/README.md Normal file
View File

@ -0,0 +1,53 @@
# Accumulate
Implement the `accumulate` operation, which, given a collection and an
operation to perform on each element of the collection, returns a new
collection containing the result of applying that operation to each element of
the input collection.
Given the collection of numbers:
- 1, 2, 3, 4, 5
And the operation:
- square a number (`x => x * x`)
Your code should be able to produce the collection of squares:
- 1, 4, 9, 16, 25
Check out the test suite to see the expected function signature.
## Restrictions
Keep your hands off that collect/map/fmap/whatchamacallit functionality
provided by your standard library!
Solve this one yourself using other basic tools instead.
Lisp specific: it's perfectly fine to use `MAPCAR` or the equivalent,
as this is idiomatic Lisp, not a library function.
## 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`
flag:
go test -bench .
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.
## Further information
For more detailed information about the Go track, including how to get help if
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
## Source
Conversation with James Edward Gray II [https://twitter.com/jeg2](https://twitter.com/jeg2)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,11 @@
package accumulate
const testVersion = 1
func Accumulate(vals []string, f func(string) string) []string {
ret := make([]string, len(vals))
for i := range vals {
ret[i] = f(vals[i])
}
return ret
}

View File

@ -0,0 +1,57 @@
package accumulate
import (
"fmt"
"strings"
"testing"
)
const targetTestVersion = 1
func echo(c string) string {
return c
}
func capitalize(word string) string {
return strings.Title(word)
}
var tests = []struct {
expected []string
given []string
converter func(string) string
description string
}{
{[]string{}, []string{}, echo, "echo"},
{[]string{"echo", "echo", "echo", "echo"}, []string{"echo", "echo", "echo", "echo"}, echo, "echo"},
{[]string{"First", "Letter", "Only"}, []string{"first", "letter", "only"}, capitalize, "capitalize"},
{[]string{"HELLO", "WORLD"}, []string{"hello", "world"}, strings.ToUpper, "strings.ToUpper"},
}
func TestTestVersion(t *testing.T) {
if testVersion != targetTestVersion {
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
}
}
func TestAccumulate(t *testing.T) {
for _, test := range tests {
actual := Accumulate(test.given, test.converter)
if fmt.Sprintf("%q", actual) != fmt.Sprintf("%q", test.expected) {
t.Fatalf("Accumulate(%q, %q): expected %q, actual %q", test.given, test.description, test.expected, actual)
}
}
}
func BenchmarkAccumulate(b *testing.B) {
b.StopTimer()
for _, test := range tests {
b.StartTimer()
for i := 0; i < b.N; i++ {
Accumulate(test.given, test.converter)
}
b.StopTimer()
}
}

View File

@ -0,0 +1,31 @@
# Error Handling
Implement various kinds of error handling and resource management.
An important point of programming is how to handle errors and close
resources even if errors occur.
This exercise requires you to handle various errors. Because error handling
is rather programming language specific you'll have to refer to the tests
for your track to see what's exactly required.
## 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`
flag:
go test -bench .
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.
## Further information
For more detailed information about the Go track, including how to get help if
you're having trouble, please visit the exercism.io [Go language page](http://exercism.io/languages/go/about).
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,57 @@
package erratum
import "io"
// These are the support types and interface definitions used in the
// implementation if your Use function. See the test suite file at
// for information on the expected implementation.
//
// Because this is part of the package "erratum", if your solution file
// is also declared in the package you will automatically have access to
// these definitions (you do not have to re-declare them).
// TransientError is an error that may occur while opening a resource via
// ResourceOpener.
type TransientError struct {
err error
}
func (e TransientError) Error() string {
return e.err.Error()
}
// FrobError is a possible error from doing some frobbing, your implementation
// will require calling your Resource's Defrob(string) method.
// When this error occurs, the FrobError's defrobTag string will contain the
// string you must pass into Defrob.
type FrobError struct {
defrobTag string
inner error
}
func (e FrobError) Error() string {
return e.inner.Error()
}
type Resource interface {
// Resource is using composition to inherit the requirements of the io.Closer
// interface. What this means is that a Resource will have a .Close() method.
io.Closer
// Frob does something with the input string.
// Because this is an incredibly badly designed system if there is an error
// it panics.
//
// The paniced error may be a FrobError in which case Defrob should be called
// with the defrobTag string.
Frob(string)
Defrob(string)
}
// ResourceOpener is a function that creates a resource.
//
// It may return a wrapped error of type TransientError. In this case the resource
// is temporarily unavailable and the caller should retry soon.
type ResourceOpener func() (Resource, error)

View File

@ -0,0 +1,35 @@
package erratum
const testVersion = 2
func Use(o ResourceOpener, inp string) (err error) {
var r Resource
moveOn := false
for !moveOn {
moveOn = true
if r, err = o(); err != nil {
switch err.(type) {
case TransientError:
moveOn = false
default:
return err
}
}
}
defer r.Close()
defer func() {
if rec := recover(); rec != nil {
switch v := rec.(type) {
case FrobError:
r.Defrob(v.defrobTag)
err = v
case error:
err = v
}
}
}()
r.Frob(inp)
return err
}

View File

@ -0,0 +1,191 @@
package erratum
import (
"errors"
"testing"
)
// Because this exercise is generally unique to each language and how it
// handles errors, most of the definition of your expected solution is provided
// here instead of the README.
// You should read this carefully (more than once) before implementation.
// Define a function `Use(o ResourceOpener, input string) error` that opens a
// resource, calls Frob(input) and closes the resource (in all cases). Your
// function should properly handle errors, as defined by the expectations of
// this test suite. ResourceOpener will be a function you may invoke directly
// `o()` in an attempt to "open" the resource. It returns a Resource and error
// value in the idiomatic Go fashion:
// https://blog.golang.org/error-handling-and-go
//
// See the ./common.go file for the definitions of Resource, ResourceOpener,
// FrobError and TransientError.
//
// There will be a few places in your Use function where errors may occur:
//
// - Invoking the ResourceOpener function passed into Use as the first
// parameter, it may fail with a TransientError, if so keep trying to open it.
// If it is some other sort of error, return it.
//
// - Calling the Frob function on the Resource returned from the ResourceOpener
// function, it may panic with a FrobError (or another type of error). If
// it is indeed a FrobError you will have to call the Resource's Defrob
// function using the FrobError's defrobTag variable as input. Either way
// return the error.
//
// Also note: if the Resource was opened successfully make sure to call its
// Close function no matter what (even if errors occur).
//
// If you are new to Go errors or panics here is a good place to start:
// https://blog.golang.org/defer-panic-and-recover
//
// You may also need to look at named return values as a helpful way to
// return error information from panic recovery:
// https://tour.golang.org/basics/7
const targetTestVersion = 2
// Little helper to let us customize behaviour of the resource on a per-test
// basis.
type mockResource struct {
close func() error
frob func(string)
defrob func(string)
}
func (mr mockResource) Close() error { return mr.close() }
func (mr mockResource) Frob(input string) { mr.frob(input) }
func (mr mockResource) Defrob(tag string) { mr.defrob(tag) }
func TestTestVersion(t *testing.T) {
if testVersion != targetTestVersion {
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
}
}
// Use should not return an error on the "happy" path.
func TestNoErrors(t *testing.T) {
var frobInput string
var closeCalled bool
mr := mockResource{
close: func() error { closeCalled = true; return nil },
frob: func(input string) { frobInput = input },
}
opener := func() (Resource, error) { return mr, nil }
inp := "hello"
err := Use(opener, inp)
if err != nil {
t.Fatalf("Unexpected error from Use: %v", err)
}
if frobInput != inp {
t.Fatalf("Wrong string passed to Frob: got %v, expected %v", frobInput, inp)
}
if !closeCalled {
t.Fatalf("Close was not called")
}
}
// Use should keep trying if a transient error is returned on open.
func TestKeepTryOpenOnTransient(t *testing.T) {
var frobInput string
mr := mockResource{
close: func() error { return nil },
frob: func(input string) { frobInput = input },
}
nthCall := 0
opener := func() (Resource, error) {
if nthCall < 3 {
nthCall++
return mockResource{}, TransientError{errors.New("some error")}
}
return mr, nil
}
inp := "hello"
err := Use(opener, inp)
if err != nil {
t.Fatalf("Unexpected error from Use: %v", err)
}
if frobInput != inp {
t.Fatalf("Wrong string passed to Frob: got %v, expected %v", frobInput, inp)
}
}
// Use should fail if a non-transient error is returned on open.
func TestFailOpenOnNonTransient(t *testing.T) {
nthCall := 0
opener := func() (Resource, error) {
if nthCall < 3 {
nthCall++
return mockResource{}, TransientError{errors.New("some error")}
}
return nil, errors.New("too awesome")
}
inp := "hello"
err := Use(opener, inp)
if err == nil {
t.Fatalf("Unexpected lack of error from Use")
}
if err.Error() != "too awesome" {
t.Fatalf("Invalid error returned from Use")
}
}
// Use should call Defrob and Close on FrobError panic from Frob
// and return the error.
func TestCallDefrobAndCloseOnFrobError(t *testing.T) {
tag := "moo"
var closeCalled bool
var defrobTag string
mr := mockResource{
close: func() error { closeCalled = true; return nil },
frob: func(input string) { panic(FrobError{tag, errors.New("meh")}) },
defrob: func(tag string) {
if closeCalled {
t.Fatalf("Close was called before Defrob")
}
defrobTag = tag
},
}
opener := func() (Resource, error) { return mr, nil }
inp := "hello"
err := Use(opener, inp)
if err == nil {
t.Fatalf("Unexpected lack of error from Use")
}
if err.Error() != "meh" {
t.Fatalf("Invalid error returned from Use")
}
if defrobTag != tag {
t.Fatalf("Wrong string passed to Defrob: got %v, expected %v", defrobTag, tag)
}
if !closeCalled {
t.Fatalf("Close was not called")
}
}
// Use should call Close but not Defrob on non-FrobError panic from Frob
// and return the error.
func TestCallCloseNonOnFrobError(t *testing.T) {
var closeCalled bool
var defrobCalled bool
mr := mockResource{
close: func() error { closeCalled = true; return nil },
frob: func(input string) { panic(errors.New("meh")) },
defrob: func(tag string) { defrobCalled = true },
}
opener := func() (Resource, error) { return mr, nil }
inp := "hello"
err := Use(opener, inp)
if err == nil {
t.Fatalf("Unexpected lack of error from Use")
}
if err.Error() != "meh" {
t.Fatalf("Invalid error returned from Use")
}
if defrobCalled {
t.Fatalf("Defrob was called")
}
if !closeCalled {
t.Fatalf("Close was not called")
}
}

View File

@ -1,26 +1,109 @@
package paasio
import (
"io"
"sync"
)
const testVersion = 3
func NewWriteCounter() WriteCounter {
w := new(WriteCounter)
return w
func NewReadCounter(r io.Reader) ReadCounter {
return &readCounter{
r: r,
lock: new(sync.Mutex),
}
}
func (w *WriteCounter) WriteCount() (int64, int) {
type readCounter struct {
r io.Reader
bytesRead int64
ops int
lock *sync.Mutex
}
func (rc *readCounter) Read(p []byte) (int, error) {
m, err := rc.r.Read(p)
rc.lock.Lock()
rc.bytesRead += int64(m)
rc.ops++
rc.lock.Unlock()
return m, err
}
func (rc *readCounter) ReadCount() (n int64, ops int) {
rc.lock.Lock()
n, ops = rc.bytesRead, rc.ops
rc.lock.Unlock()
return n, ops
}
func NewWriteCounter(w io.Writer) WriteCounter {
return &writeCounter{
w: w,
lock: new(sync.Mutex),
}
}
type writeCounter struct {
w io.Writer
bytesWrote int64
ops int
lock *sync.Mutex
}
func (wc *writeCounter) Write(p []byte) (int, error) {
m, err := wc.w.Write(p)
wc.lock.Lock()
wc.bytesWrote += int64(m)
wc.ops++
wc.lock.Unlock()
return m, err
}
func (wc *writeCounter) WriteCount() (n int64, ops int) {
wc.lock.Lock()
n, ops = wc.bytesWrote, wc.ops
wc.lock.Unlock()
return n, ops
}
type ReadWriter interface {
io.Reader
io.Writer
}
func NewReadWriteCounter(rw ReadWriter) ReadWriteCounter {
return &readWriteCounter{
r: NewReadCounter(rw),
w: NewWriteCounter(rw),
}
}
type readWriteCounter struct {
r ReadCounter
w WriteCounter
}
func (rw *readWriteCounter) Read(p []byte) (int, error) {
return rw.r.Read(p)
}
func (rw *readWriteCounter) Write(p []byte) (int, error) {
return rw.w.Write(p)
}
func (rw *readWriteCounter) ReadCount() (n int64, ops int) {
return rw.r.ReadCount()
}
func (rw *readWriteCounter) WriteCount() (n int64, ops int) {
return rw.w.WriteCount()
}
func (nr *nopReader) ReadCount() (n int64, ops int) {
return 0, 0
}
func NewReadCounter() ReadCounter {
r := new(ReadCounter)
return r
}
func (r *ReadCounter) ReadCount() (int64, int) {
func (nw *nopWriter) WriteCount() (n int64, ops int) {
return 0, 0
}
func NewReadWriteCounter() *ReadWriteCounter {
r := new(ReadWriteCounter)
return r
}

59
go/pov/README.md Normal file
View File

@ -0,0 +1,59 @@
# Pov
Reparent a graph on a selected node
# Tree Reparenting
This exercise is all about re-orientating a graph to see things from a different
point of view. For example family trees are usually presented from the
ancestor's perspective:
```
+------0------+
| | |
+-1-+ +-2-+ +-3-+
| | | | | |
4 5 6 7 8 9
```
But the same information can be presented from the perspective of any other node
in the graph, by pulling it up to the root and dragging its relationships along
with it. So the same graph from 6's perspective would look like:
```
6
|
+-----2-----+
| |
7 +-----0-----+
| |
+-1-+ +-3-+
| | | |
4 5 8 9
```
This lets us more simply describe the paths between two nodes. So for example
the path from 6-9 (which in the first graph goes up to the root and then down to
a different leaf node) can be seen to follow the path 6-2-0-3-9
This exercise involves taking an input graph and re-orientating it from the point
of view of one of the nodes.
To run the tests simply run the command `go test` in the exercise directory.
If the test suite contains benchmarks, you can run these with the `-bench`
flag:
go test -bench .
For more detailed info about the Go track see the [help
page](http://exercism.io/languages/go).
## Source
Adaptation of exercise from 4clojure [https://www.4clojure.com/](https://www.4clojure.com/)
## Submitting Incomplete Problems
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

122
go/pov/pov.go Normal file
View File

@ -0,0 +1,122 @@
package pov
const testVersion = 2
type Graph struct {
leaves []Node
}
func New() *Graph {
g := new(Graph)
return g
}
func (g *Graph) GetNode(lbl string) *Node {
for i := range g.leaves {
if n := g.leaves[i].GetNode(lbl); n != nil {
return n
}
}
return nil
}
func (g *Graph) AddNode(lbl string) {
g.leaves = append(g.leaves, Node{label: lbl})
}
func (g *Graph) addRealNode(n *Node) {
g.leaves = append(g.leaves, n)
}
func (g *Graph) AddArc(from, to string) {
if n := g.GetNode(to); n != nil {
n.AddNode(from)
}
}
func (g *Graph) ArcList() []string {
var ret []string
for i := range g.leaves {
ret = append(ret, g.leaves[i].ArcList()...)
}
return ret
}
func (g *Graph) ChangeRoot(oldRoot, newRoot string) *Graph {
// First of all, find the newRoot node
ret := New()
// The new graph will start with newRoot and have newRoot's leaves
if rt := g.GetNode(newRoot); rt == nil {
return ret
}
// It'll have one more leaf, it's parent node
ret.AddNode(rt)
return g
}
func (g *Graph) getPath(from, to string) []string {
var ret []string
// Get the 'from' node
frNode := g.GetNode(from)
if frNode == nil {
// Couldn't find the starting node
return ret
}
// Just in case we got the same value for both
if from == to {
return []string{from}
}
// Found it
return frNode.getPath(to)
}
type Node struct {
label string
leaves []Node
}
func (n *Node) AddNode(lbl string) {
n.leaves = append(n.leaves, Node{label: lbl})
}
func (n *Node) GetNode(lbl string) *Node {
if n.label == lbl {
return n
}
for i := range n.leaves {
if r := n.leaves[i].GetNode(lbl); r != nil {
return r
}
}
return nil
}
func (n *Node) ArcList() []string {
var ret []string
for i := range n.leaves {
ret = append(ret, n.leaves[i].label+" -> "+n.label)
ret = append(ret, n.leaves[i].ArcList()...)
}
return ret
}
func (n *Node) getPath(to string) []string {
ret := []string{n.label}
if n.label == to {
return ret
}
var i int
var found bool
for i = range n.leaves {
if n.leaves[i].GetNode(to) != nil {
found = true
break
}
}
if !found {
// We didn't find a path... :(
return ret
}
// n.leaves[i] should be the right leaf now
return append(ret, n.leaves[i].getPath(to)...)
}

295
go/pov/pov_test.go Normal file
View File

@ -0,0 +1,295 @@
package pov
import (
"reflect"
"sort"
"testing"
)
const targetTestVersion = 2
// POV / reparent / change root of a tree
//
// API:
// type Graph
// func New() *Graph
// func (*Graph) AddNode(nodeLabel string)
// func (*Graph) AddArc(from, to string)
// func (*Graph) ArcList() []string
// func (*Graph) ChangeRoot(oldRoot, newRoot string) *Graph
//
// The type name is Graph because you'll probably be implementing a general
// directed graph representation, although the test program will only use
// it to create a tree. The term "arc" is used here to mean a directed edge.
//
// The test program will create a graph with New, then use AddNode to add
// leaf nodes. After that it will use AddArc to construct the rest of the tree
// from the bottom up. That is, the `to` argument will aways specify a node
// that has already been added.
//
// ArcList is a dump method to let the test program see your graph. It must
// return a list of all arcs in the graph. Format each arc as a single string
// like "from -> to". The test program can then easily sort the list and
// compare it to an expected result. You do not need to bother with sorting
// the list yourself.
//
// All this graph construction and dumping must be working before you start
// on the interesting part of the exercise, so it is tested separately as
// a first test.
//
// API function ChangeRoot does the interesting part of the exercise.
// OldRoot is passed (as a convenience) and you must return a graph with
// newRoot as the root. You can modify the original graph in place and
// return it or create a new graph and return that. If you return a new
// graph you are free to consume or destroy the original graph. Of course
// it's nice to leave it unmodified.
type arc struct{ fr, to string }
type testCase struct {
description string
leaves []string
arcPairs []arc
root string
arcStrings []string
reRooted []string
}
var testCases = []testCase{
{
description: "singleton",
leaves: []string{"x"},
arcPairs: nil,
root: "x",
arcStrings: nil,
reRooted: nil,
},
{
description: "simple tree",
leaves: []string{"sibling", "x"},
arcPairs: []arc{
{"parent", "sibling"},
{"parent", "x"},
},
root: "parent",
arcStrings: []string{
"parent -> sibling",
"parent -> x",
},
reRooted: []string{
"parent -> sibling",
"x -> parent",
},
},
{
description: "large flat",
leaves: []string{"sib-a", "sib-b", "x", "sib-c", "sib-d"},
arcPairs: []arc{
{"parent", "sib-a"},
{"parent", "sib-b"},
{"parent", "x"},
{"parent", "sib-c"},
{"parent", "sib-d"},
},
root: "parent",
arcStrings: []string{
"parent -> sib-a",
"parent -> sib-b",
"parent -> sib-c",
"parent -> sib-d",
"parent -> x",
},
reRooted: []string{
"parent -> sib-a",
"parent -> sib-b",
"parent -> sib-c",
"parent -> sib-d",
"x -> parent",
},
},
{
description: "deeply nested",
leaves: []string{"x"},
arcPairs: []arc{
{"level-4", "x"},
{"level-3", "level-4"},
{"level-2", "level-3"},
{"level-1", "level-2"},
{"level-0", "level-1"},
},
root: "level-0",
arcStrings: []string{
"level-0 -> level-1",
"level-1 -> level-2",
"level-2 -> level-3",
"level-3 -> level-4",
"level-4 -> x",
},
reRooted: []string{
"level-1 -> level-0",
"level-2 -> level-1",
"level-3 -> level-2",
"level-4 -> level-3",
"x -> level-4",
},
},
{
description: "cousins",
leaves: []string{"sib-1", "x", "sib-2", "cousin-1", "cousin-2"},
arcPairs: []arc{
{"parent", "sib-1"},
{"parent", "x"},
{"parent", "sib-2"},
{"aunt", "cousin-1"},
{"aunt", "cousin-2"},
{"grand-parent", "parent"},
{"grand-parent", "aunt"},
},
root: "grand-parent",
arcStrings: []string{
"aunt -> cousin-1",
"aunt -> cousin-2",
"grand-parent -> aunt",
"grand-parent -> parent",
"parent -> sib-1",
"parent -> sib-2",
"parent -> x",
},
reRooted: []string{
"aunt -> cousin-1",
"aunt -> cousin-2",
"grand-parent -> aunt",
"parent -> grand-parent",
"parent -> sib-1",
"parent -> sib-2",
"x -> parent",
},
},
{
description: "target with children",
leaves: []string{"child-1", "child-2", "nephew", "niece",
"2nd-cousin-1", "2nd-cousin-2", "2nd-cousin-3", "2nd-cousin-4"},
arcPairs: []arc{
{"x", "child-1"},
{"x", "child-2"},
{"sibling", "nephew"},
{"sibling", "niece"},
{"cousin-1", "2nd-cousin-1"},
{"cousin-1", "2nd-cousin-2"},
{"cousin-2", "2nd-cousin-3"},
{"cousin-2", "2nd-cousin-4"},
{"parent", "x"},
{"parent", "sibling"},
{"aunt", "cousin-1"},
{"aunt", "cousin-2"},
{"grand-parent", "parent"},
{"grand-parent", "aunt"},
},
root: "grand-parent",
arcStrings: []string{
"aunt -> cousin-1",
"aunt -> cousin-2",
"cousin-1 -> 2nd-cousin-1",
"cousin-1 -> 2nd-cousin-2",
"cousin-2 -> 2nd-cousin-3",
"cousin-2 -> 2nd-cousin-4",
"grand-parent -> aunt",
"grand-parent -> parent",
"parent -> sibling",
"parent -> x",
"sibling -> nephew",
"sibling -> niece",
"x -> child-1",
"x -> child-2",
},
reRooted: []string{
"aunt -> cousin-1",
"aunt -> cousin-2",
"cousin-1 -> 2nd-cousin-1",
"cousin-1 -> 2nd-cousin-2",
"cousin-2 -> 2nd-cousin-3",
"cousin-2 -> 2nd-cousin-4",
"grand-parent -> aunt",
"parent -> grand-parent",
"parent -> sibling",
"sibling -> nephew",
"sibling -> niece",
"x -> child-1",
"x -> child-2",
"x -> parent",
},
},
}
func (tc testCase) graph() *Graph {
g := New()
for _, l := range tc.leaves {
g.AddNode(l)
}
for _, a := range tc.arcPairs {
g.AddArc(a.fr, a.to)
}
return g
}
func (tc testCase) testResult(got, want []string, msg string, t *testing.T) {
if len(got)+len(want) == 0 {
return
}
gs := append([]string{}, got...)
sort.Strings(gs)
if reflect.DeepEqual(gs, want) {
return
}
// test has failed
t.Log(tc.description, "test case")
t.Log(msg)
t.Logf("got %d arcs:", len(got))
for _, s := range got {
t.Log(" ", s)
}
t.Logf("that result sorted:")
for _, s := range gs {
t.Log(" ", s)
}
t.Logf("want %d arcs:", len(want))
for _, s := range want {
t.Log(" ", s)
}
t.FailNow()
}
func TestConstruction(t *testing.T) {
if testVersion != targetTestVersion {
t.Fatalf("Found testVersion = %v, want %v", testVersion, targetTestVersion)
}
for _, tc := range testCases {
got := tc.graph().ArcList()
want := tc.arcStrings
tc.testResult(got, want, "incorrect graph construction", t)
}
}
func TestChangeRoot(t *testing.T) {
for _, tc := range testCases {
got := tc.graph().ChangeRoot(tc.root, "x").ArcList()
want := tc.reRooted
tc.testResult(got, want, "incorrect root change", t)
}
}
func BenchmarkConstructOnlyNoChange(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testCases {
tc.graph()
}
}
}
func BenchmarkConstructAndChangeRoot(b *testing.B) {
for i := 0; i < b.N; i++ {
for _, tc := range testCases {
tc.graph().ChangeRoot(tc.root, "x")
}
}
}

View File

@ -1 +0,0 @@
example

Binary file not shown.

View File

@ -0,0 +1 @@
{}

View File

@ -3,5 +3,5 @@
#
def hello(name=''):
return
def hello(name='World'):
return 'Hello, '+name+'!'

30
python/isogram/README.md Normal file
View File

@ -0,0 +1,30 @@
# Isogram
Determine if a word or phrase is an isogram.
An isogram (also known as a "nonpattern word") is a word or phrase without a repeating letter.
Examples of isograms:
- lumberjacks
- background
- downstream
The word *isograms*, however, is not an isogram, because the s repeats.
### Submitting Exercises
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
For more detailed information about running tests, code style and linting,
please see the [help page](http://exercism.io/languages/python).
## Source
Wikipedia [https://en.wikipedia.org/wiki/Isogram](https://en.wikipedia.org/wiki/Isogram)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

View File

@ -0,0 +1,2 @@
def is_isogram():
pass

View File

@ -0,0 +1,39 @@
import unittest
from isogram import is_isogram
# test cases adapted from `x-common//canonical-data.json` @ version: 1.1.0
class TestIsogram(unittest.TestCase):
def test_empty_string(self):
self.assertTrue(is_isogram(""))
def test_isogram_with_only_lower_case_characters(self):
self.assertTrue(is_isogram("isogram"))
def test_word_with_one_duplicated_character(self):
self.assertFalse(is_isogram("eleven"))
def test_longest_reported_english_isogram(self):
self.assertTrue(is_isogram("subdermatoglyphic"))
def test_word_with_duplicated_character_in_mixed_case(self):
self.assertFalse(is_isogram("Alphabet"))
def test_hypothetical_isogrammic_word_with_hyphen(self):
self.assertTrue(is_isogram("thumbscrew-japingly"))
def test_isogram_with_duplicated_non_letter_character(self):
self.assertTrue(is_isogram("Hjelmqvist-Gryb-Zock-Pfund-Wax"))
def test_made_up_name_that_is_an_isogram(self):
self.assertTrue(is_isogram("Emily Jung Schwartzkopf"))
def test_duplicated_character_in_the_middle(self):
self.assertFalse(is_isogram("accentor"))
if __name__ == '__main__':
unittest.main()

1
python/leap/.cache/v/cache/lastfailed vendored Normal file
View File

@ -0,0 +1 @@
{}

44
python/leap/README.md Normal file
View File

@ -0,0 +1,44 @@
# Leap
Given a year, report if it is a leap year.
The tricky thing here is that a leap year in the Gregorian calendar occurs:
```plain
on every year that is evenly divisible by 4
except every year that is evenly divisible by 100
unless the year is also evenly divisible by 400
```
For example, 1997 is not a leap year, but 1996 is. 1900 is not a leap
year, but 2000 is.
If your language provides a method in the standard library that does
this look-up, pretend it doesn't exist and implement it yourself.
## Notes
Though our exercise adopts some very simple rules, there is more to
learn!
For a delightful, four minute explanation of the whole leap year
phenomenon, go watch [this youtube video][video].
[video]: http://www.youtube.com/watch?v=xX96xng7sAE
### Submitting Exercises
Note that, when trying to submit an exercise, make sure the solution is in the `exercism/python/<exerciseName>` directory.
For example, if you're submitting `bob.py` for the Bob exercise, the submit command would be something like `exercism submit <path_to_exercism_dir>/python/bob/bob.py`.
For more detailed information about running tests, code style and linting,
please see the [help page](http://exercism.io/languages/python).
## Source
JavaRanch Cattle Drive, exercise 3 [http://www.javaranch.com/leap.jsp](http://www.javaranch.com/leap.jsp)
## Submitting Incomplete Solutions
It's possible to submit an incomplete solution so you can see how others have completed the exercise.

Binary file not shown.

2
python/leap/leap.py Normal file
View File

@ -0,0 +1,2 @@
def is_leap_year(yr):
return yr % 4 == 0 and (yr % 100 != 0 or yr % 400 == 0)

23
python/leap/leap_test.py Normal file
View File

@ -0,0 +1,23 @@
import unittest
from leap import is_leap_year
# test cases adapted from `x-common//canonical-data.json` @ version: 1.0.0
class YearTest(unittest.TestCase):
def test_year_not_divisible_by_4(self):
self.assertFalse(is_leap_year(2015))
def test_year_divisible_by_4_not_divisible_by_100(self):
self.assertTrue(is_leap_year(2016))
def test_year_divisible_by_100_not_divisible_by_400(self):
self.assertFalse(is_leap_year(2100))
def test_year_divisible_by_400(self):
self.assertTrue(is_leap_year(2000))
if __name__ == '__main__':
unittest.main()