Explorar el Código

K5 go primes_in_numbers

Frederic G. MARAND hace 4 años
padre
commit
2d2fb2a85f

+ 11 - 0
go/.idea/runConfigurations/k5_primes_in_numbers.xml

@@ -0,0 +1,11 @@
+<component name="ProjectRunConfigurationManager">
+  <configuration default="false" name="k5 primes in numbers" type="GoTestRunConfiguration" factoryName="Go Test">
+    <module name="codewars" />
+    <working_directory value="$PROJECT_DIR$/" />
+    <go_parameters value="-i " />
+    <framework value="gotest" />
+    <kind value="PACKAGE" />
+    <package value="code.osinet.fr/fgm/codewars/kyu5/primes_in_numbers" />
+    <method v="2" />
+  </configuration>
+</component>

+ 86 - 0
go/kyu5/primes_in_numbers/k.go

@@ -0,0 +1,86 @@
+package kata
+
+import (
+	"fmt"
+	"math"
+	"strings"
+)
+
+/*
+trimPrimes removes the impossible primes from the list against which to check.
+  - primes: the current list
+  - low: the lowest possible value for a valid prime
+  - n: the maximum possible value for a valid prime
+*/
+
+func trimPrimes(primes []int, low, high int) []int {
+	var res []int
+	lowIndex, highIndex := 0, int(math.Ceil(math.Sqrt(float64(high))))
+	for i, prime := range primes {
+		if prime < low {
+			lowIndex = i
+		}
+		if prime > highIndex {
+			highIndex = i
+			break
+		}
+	}
+	if highIndex > len(primes) {
+		res = primes[lowIndex:]
+	} else {
+		res = primes[lowIndex:highIndex]
+	}
+	return res
+}
+
+func trialDivision(n int) []int {
+	limit := int(math.Ceil(math.Sqrt(float64(n))))
+	primes := Primes(limit)
+	var divisors []int
+	for _, prime := range primes {
+		for n > 1 {
+			if n%prime == 0 {
+				divisors = append(divisors, prime)
+				n /= prime
+				primes = trimPrimes(primes, prime, n)
+				continue
+			}
+			primes = trimPrimes(primes, prime+2, n)
+			break
+		}
+	}
+	if n > 1 {
+		divisors = append(divisors, n)
+	}
+	return divisors
+}
+
+func format(curr, power int) string {
+	if power == 1 {
+		return fmt.Sprintf("(%d)", curr)
+	} else {
+		return fmt.Sprintf("(%d**%d)", curr, power)
+	}
+}
+
+func PrimeFactors(n int) string {
+	if n <= 1 {
+		return ""
+	}
+	factors := trialDivision(n)
+	var rows []string
+	curr := 1
+	power := 1
+	for _, divisor := range factors {
+		if divisor == curr {
+			power++
+		} else {
+			rows = append(rows, format(curr, power))
+			curr = divisor
+			power = 1
+		}
+	}
+	rows = append(rows, format(curr, power))
+	res := strings.Join(rows[1:], "")
+	return res
+}

+ 24 - 0
go/kyu5/primes_in_numbers/k_test.go

@@ -0,0 +1,24 @@
+package kata_test
+
+import (
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	. "code.osinet.fr/fgm/codewars/kyu5/primes_in_numbers"
+)
+
+func dotest(n int, exp string) {
+	var ans = PrimeFactors(n)
+	Expect(ans).To(Equal(exp))
+}
+
+var _ = Describe("ConvertFracts", func() {
+	It("Degenerate", func() {
+		dotest(1, "")
+	})
+	It("Basic tests", func() {
+		dotest(7775460, "(2**2)(3**3)(5)(7)(11**2)(17)")
+		dotest(79340, "(2**2)(5)(3967)")
+
+	})
+})

+ 46 - 0
go/kyu5/primes_in_numbers/primes_in_numbers_suite_test.go

@@ -0,0 +1,46 @@
+package kata_test
+
+import (
+	"fmt"
+	"testing"
+
+	. "github.com/onsi/ginkgo"
+	. "github.com/onsi/gomega"
+
+	kata "code.osinet.fr/fgm/codewars/kyu5/primes_in_numbers"
+)
+
+func TestPrimesInNumbers(t *testing.T) {
+	RegisterFailHandler(Fail)
+	RunSpecs(t, "PrimesInNumbers Suite")
+}
+
+func ZTestPrimes(t *testing.T) {
+	type checkType struct {
+		limit    int
+		expected []int
+	}
+	checks := [...]checkType{
+		{0, []int{}},
+		{1, []int{}},
+		{2, []int{2}},
+		{10, []int{2, 3, 5, 7}},
+	}
+	for _, check := range checks {
+		t.Run(fmt.Sprintf("Limit %d", check.limit), func(t *testing.T) {
+			t.Parallel()
+			actual := kata.Primes(check.limit)
+			if len(actual) != len(check.expected) {
+				t.Log(actual)
+				t.FailNow()
+			}
+			for i := 0; i < len(actual); i++ {
+				if check.expected[i] != actual[i] {
+					t.Log(actual)
+					t.Fail()
+				}
+			}
+
+		})
+	}
+}

+ 45 - 0
go/kyu5/primes_in_numbers/sieve1.go

@@ -0,0 +1,45 @@
+package kata
+
+// Based on the Go classical concurrent prime sieve
+// See https://golang.org/test/chan/sieve1.go
+func Primes(limit int) []int {
+	// Generate numbers from 2 to limit, included.
+	gen := func(ch chan<- int, limit int) {
+		for i := 2; i <= limit; i++ {
+			ch <- i
+		}
+		close(ch)
+	}
+	// Remove divisible numbers
+	//  - in: numbers source
+	//  - out: numbers sink
+	//  - prime: prime by which to attempt modulo
+	filter := func(in <-chan int, out chan<- int, prime int) {
+		for {
+			candidate, ok := <-in
+			// Source was closed.
+			if !ok {
+				break
+			}
+			if candidate%prime != 0 {
+				out <- candidate
+			}
+		}
+		close(out)
+	}
+
+	genChan := make(chan int)
+	go gen(genChan, limit)
+	var primes []int
+	for i := 0; ; i++ {
+		prime, ok := <-genChan
+		if !ok {
+			break
+		}
+		primes = append(primes, prime)
+		filterChan := make(chan int)
+		go filter(genChan, filterChan, prime)
+		genChan = filterChan
+	}
+	return primes
+}