ruby-anagrams 0.0.1 → 0.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: b4354f4fdcda04c67e8f3b2e11afbe9b6999fc22
4
- data.tar.gz: 7cf6680ff7f4de0aa5aff21768852fab28e51d7a
3
+ metadata.gz: ec31af73831e6d121c7a68d31d6f034d2ce8a056
4
+ data.tar.gz: 8199632ddb78960c4df770470f8228837967d305
5
5
  SHA512:
6
- metadata.gz: 28216d0fefce0b01b630e56e7eec4d9cf330183c7e76666cd94db7bd17fd8bd8dc5b7a14d7c6121069ec35a70bfce2952ca5aac6780f20b27582e192339b3ada
7
- data.tar.gz: dceb898b96b5f0b67cdbd014fb1d8bde14586725ed18c35f4f5d6128037c725cf3c3f027067def25a37502b4e26f5be3c131cdbf588c62cf110c0ccb549b01b9
6
+ metadata.gz: 71362f70f599bd5ed3ee10342614825ae306b0fea0f304952776c60d9787e2ebc890eb4642a25c3e92a1db8f94e17b418c195595b6c280a979f29118fbc114e2
7
+ data.tar.gz: 2f02a8847de091de0886aa97921742e83888476adefd1258788c633e5b3e0f6d82a9f22c7d8112ccdcfab5d25a1838a995918ac5794387192c78dc9d260d7cdf
@@ -7,85 +7,64 @@ module RubyAnagrams
7
7
  # A Hash associating symbols with unique prime numbers.
8
8
  SYM_PRIMES = (:a..:z).to_a.zip(Prime.first(26)).to_h
9
9
 
10
- # Returns all words in the trie data structure that are anagrams
11
- # of the string provided. "*" indicates a wildcard.
12
- # @note Default behavior finds complete anagrams that use every character
13
- # in the string. Partial anagrams can be included by setting include_partial
14
- # to true.
15
- # @example without partial anagrams
16
- # root << "rise"
17
- # root << "sire"
18
- # root << "rie"
19
- # #anagrams "rise" #=> ['rise', 'sire']
20
- # @example with partial anagrams
21
- # root << "rise"
22
- # root << "sire"
23
- # root << "rie"
24
- # #anagrams "rise", include_partial: true #=> ['rie', 'rise', 'sire']
25
- # @example with wildcards
26
- # root << "bin"
27
- # root << "ban"
28
- # root << "bun"
29
- # #anagrams "b*n" #=> ['ban', 'bin', 'bun']
30
- # @param string [String] the string to find anagrams of.
31
- # @param include_partial [Boolean] include partial anagrams?
32
- # @return [Array<String>] all anagrams of the given string.
33
- def anagrams string, include_partial: false
34
- symbols = str_to_sym_a string
35
- anagrams = []
36
- find_symbol_permutations(symbols).each do |permutation|
37
- anagrams.concat find_anagrams(as_product(permutation), include_partial: include_partial)
10
+ class << self
11
+ # Returns the product of each symbol's associated prime number.
12
+ # @param symbols [Array<Symbol>] the symbols to multiply.
13
+ # @return [Integer] the product of each symbol's associated prime number.
14
+ def sym_a_to_product symbols
15
+ symbols.inject(1) { |acc,sym| acc * SYM_PRIMES[sym] }
38
16
  end
39
- anagrams.uniq.sort
40
- end
41
17
 
42
- protected
43
- # Returns anagrams in the trie data structure by performing depth-first search,
44
- # following subtrees whose symbol's associated prime number is a prime factor
45
- # of the product representing a string. The words of visited terminal nodes
46
- # are returned as an array.
47
- # @note Default behavior finds words that consume all prime factors
48
- # of the given product. Words that do not consume all prime factors can
49
- # be included by setting include_partial to true.
50
- # @param product [Integer] the product representing the string to find
51
- # anagrams of.
52
- # @param include_partial [Boolean] include partial anagrams?
53
- # @return [Array<String>] all anagrams whose product divides into the given
54
- # product.
55
- def find_anagrams product, include_partial: false
56
- anagrams = []
57
- anagrams << word if terminal? && (include_partial ? true : product == 1)
58
- @children.each do |symbol,child|
59
- if product % SYM_PRIMES[symbol] == 0
60
- anagrams += child.find_anagrams(product / SYM_PRIMES[symbol], include_partial: include_partial)
61
- end
18
+ # Returns all permutations of a symbol array, where "*" wildcards
19
+ # are replaced with symbols in the trie's alphabet.
20
+ # @param symbols [Array<Symbol>] the symbols to permute.
21
+ # @return [Array<Array<Symbol>>] the permutations.
22
+ def sym_a_permutations symbols
23
+ permutations = []
24
+ base_symbols = symbols.reject { |s| s == :* }
25
+ wildcard_permutations = (:a..:z).to_a.repeated_permutation(symbols.count :*)
26
+ wildcard_permutations.each do |permutation|
27
+ permutations << permutation.concat(base_symbols)
62
28
  end
63
- anagrams
29
+ permutations.empty? ? [symbols] : permutations
64
30
  end
31
+ end
65
32
 
66
- # Returns all permutations of the given set of symbols, where "*" wildcards
67
- # are replaced with all possible permutations of symbols in the trie's
68
- # alphabet.
69
- # @example with 1 wildcard
70
- # alphabet = [:a, :b, :c]
71
- # #find_symbol_permutations [:a, :*, :c] #=> [[:a, :a, :c], [:a, :b, :c], [:a, :c, :c]]
72
- # @param symbols [Array<Symbol>] the symbols to permute.
73
- # @return [Array<Array<Symbol>>] all permutations of the symbols.
74
- def find_symbol_permutations symbols
75
- symbol_permutations = []
76
- non_wild_symbols = symbols.reject{|s| s == :*}
77
- (:a..:z).to_a.repeated_permutation(symbols.count :*).each do |permutation|
78
- symbol_permutations << non_wild_symbols + permutation
79
- end
80
- symbol_permutations.empty? ? [symbols] : symbol_permutations
33
+ # Returns all string anagrams of the given symbol array by calling
34
+ # #anagrams_by_product on all permutations of the symbol array.
35
+ # @note Default behavior only includes complete anagrams. Partial anagrams
36
+ # can be included by setting partial to true.
37
+ # @param symbols [Array<Symbol>] the symbols to find anagrams for.
38
+ # @param partial [Boolean] include partial anagrams?
39
+ # @return [Array<Array<String>>] all anagrams of the symbols.
40
+ def search_for_anagrams symbols, partial: partial
41
+ anagrams = []
42
+ Anagrams.sym_a_permutations(symbols).each do |permutation|
43
+ product = Anagrams.sym_a_to_product permutation
44
+ anagrams.concat anagrams_by_product(product, partial: partial)
81
45
  end
46
+ anagrams.uniq.sort
47
+ end
82
48
 
83
- # Returns the product of each symbol's associated prime number.
84
- # @param symbols [Array<Symbol>] the symbols to multiply.
85
- # @return [Integer] the product of each symbol's associated prime number.
86
- def as_product symbols
87
- symbols.inject(1) { |acc,sym| acc * SYM_PRIMES[sym] }
49
+ # Depth-first searches the trie data structure for anagrams based on their
50
+ # node's associated prime number. Returns an array of anagrams whose product
51
+ # divides into the given product.
52
+ # @note Default behavior only includes words with a product equal to the
53
+ # given product. Words that are divisors of the given product can be
54
+ # included by setting partial to true.
55
+ # @param product [Integer] a product of a symbol array.
56
+ # @param partial [Boolean] include partial anagrams?
57
+ # @return [Array<String>] all anagrams of the given product.
58
+ def anagrams_by_product product, partial: partial
59
+ anagrams = []
60
+ anagrams << word if terminal? && (partial ? true : product == 1)
61
+ @children.each do |symbol,child|
62
+ if product % SYM_PRIMES[symbol] == 0
63
+ anagrams += child.anagrams_by_product(product / SYM_PRIMES[symbol], partial: partial)
64
+ end
88
65
  end
66
+ anagrams
67
+ end
89
68
 
90
69
  end
91
70
  end
@@ -9,11 +9,9 @@ module RubyAnagrams
9
9
  # an Enumerator is returned.
10
10
  # @return [Enumerator] the enumerator for the words in the trie data structure.
11
11
  def each &block
12
- enumerator = Enumerator.new do |y|
13
- y << word if terminal?
14
- @children.each_value do |child|
15
- child.each { |word| y << word }
16
- end
12
+ enumerator = Enumerator.new do |yielder|
13
+ yielder << word if terminal?
14
+ @children.each_value { |child| child.each { |word| yielder << word } }
17
15
  end
18
16
  block.nil? ? enumerator : enumerator.each(&block)
19
17
  end
@@ -1,8 +1,8 @@
1
- # Namespace for the Ruby-Anagrams gem.
2
1
  module RubyAnagrams
3
2
  # A representation of the Root node of the trie data structure.
4
3
  # @author Connor Lay
5
4
  class Root < Node
5
+
6
6
  # Creates a new trie.
7
7
  # @param path [String, nil] the path to a dictionary text file.
8
8
  # @return [Root] the Root node of the trie just created.
@@ -19,25 +19,46 @@ module RubyAnagrams
19
19
  # @param word [String] the new word to add to the trie.
20
20
  # @return [String] the word just added to the trie.
21
21
  def << word
22
- symbols = str_to_sym_a word
22
+ symbols = word.to_sym_a
23
23
  add_to_subtree symbols
24
24
  end
25
25
 
26
+ alias :add :<<
27
+
26
28
  # If the trie contains the word.
27
29
  # @param word [String] the word to search for.
28
30
  # @return [Boolean] true if the word is found, false otherwise.
29
31
  def include? word
30
- symbols = str_to_sym_a word
32
+ symbols = word.to_sym_a
31
33
  search_subtree symbols
32
34
  end
33
35
 
34
- # Returns a symbol array based on the chatacters of a string.
35
- # @example
36
- # str_to_sym_a "apple" #=> [:a, :p, :p, :l, :e]
37
- # @param string [String] the string to process
38
- # @return [Array<Symbol>] an array of symbols
39
- def str_to_sym_a string
40
- string.chars.map { |char| char.to_sym }
36
+ alias :contains? :include?
37
+
38
+ # Returns all anagrams of the given word. Wildcards are indicated with "*".
39
+ # @note Default behavior only includes complete anagrams. Partial anagrams
40
+ # can be included by setting partial to true.
41
+ # @example without partial anagrams
42
+ # root << "rise"
43
+ # root << "sire"
44
+ # root << "rie"
45
+ # #anagrams "rise" #=> ['rise', 'sire']
46
+ # @example with partial anagrams
47
+ # root << "rise"
48
+ # root << "sire"
49
+ # root << "rie"
50
+ # #anagrams "rise", partial: true #=> ['rie', 'rise', 'sire']
51
+ # @example with wildcards
52
+ # root << "bin"
53
+ # root << "ban"
54
+ # root << "bun"
55
+ # #anagrams "b*n" #=> ['ban', 'bin', 'bun']
56
+ # @param word [String] the word to find anagrams for.
57
+ # @param partial [Boolean] include partial anagrams?
58
+ # @return [Array<String>] anagrams of word.
59
+ def anagrams word, partial: false
60
+ symbols = word.to_sym_a
61
+ search_for_anagrams symbols, partial: partial
41
62
  end
42
63
 
43
64
  end
@@ -0,0 +1,9 @@
1
+ class String
2
+ # Returns a symbol array representation of the reciever's characters.
3
+ # @example
4
+ # "apple".to_sym_a #=> [:a, :p, :p, :l, :e]
5
+ # @return [Array<Symbol>] an array of symbols
6
+ def to_sym_a
7
+ self.chars.map { |char| char.to_sym }
8
+ end
9
+ end
@@ -14,33 +14,41 @@ module RubyAnagrams
14
14
  nodes
15
15
  end
16
16
 
17
+ # Descends the trie data structure following the given sequence of symbols.
18
+ # The last node visited is returned, either because it is a leaf or there
19
+ # are no symbols left.
20
+ # @note This method alters the symbol array.
21
+ # @param symbols [Array<Symbol>] the symbol sequence to follow.
22
+ # @return [Node] the last node visited.
23
+ def descend symbols
24
+ return self unless symbol = symbols[0]
25
+ return self unless child = @children[symbol]
26
+ symbols.slice! 0
27
+ child.descend symbols
28
+ end
29
+
17
30
  protected
18
31
  # Descends the trie data structure, adding nodes when needed, for a given
19
32
  # sequence of symbols. The last node visited is designated as a terminal.
20
33
  # @param symbols [Array<Symbol>] the symbol sequence to follow.
21
34
  # @return [String] the word represented by the last node visited.
22
35
  def add_to_subtree symbols
23
- if symbols.empty?
24
- terminal!
25
- return word
26
- end
27
- s = symbols.slice! 0
28
- unless child = @children[s]
29
- child = Node.new s, self
30
- @children[s] = child
36
+ current = descend symbols
37
+ symbols.each do |symbol|
38
+ current[symbol] = Node.new symbol, current
39
+ current = current[symbol]
31
40
  end
32
- child.add_to_subtree symbols
41
+ current.terminal!
42
+ current.word
33
43
  end
34
44
 
35
- # Performs depth-first search, following a sequence of symbols, on the trie
36
- # data structure. Returns true if the last node visited is a terminal.
45
+ # Depth-first searches the trie data structure for a node representing a
46
+ # given sequence of symbols.
37
47
  # @param symbols [Array<Symbol>] the symbol sequence to follow.
38
48
  # @return [Boolean] true if the last node visited is a terminal, false otherwise.
39
49
  def search_subtree symbols
40
- return true if symbols.empty? && terminal?
41
- s = symbols.slice! 0
42
- return false unless child = @children[s]
43
- child.search_subtree symbols
50
+ current = descend symbols
51
+ current.terminal? && symbols.empty?
44
52
  end
45
53
 
46
54
  end
@@ -1,5 +1,10 @@
1
+ require_relative 'anagrams/string_to_symbol_array'
1
2
  require_relative 'anagrams/subtrees'
2
3
  require_relative 'anagrams/enumerable'
3
4
  require_relative 'anagrams/anagrams'
4
5
  require_relative 'anagrams/node'
5
- require_relative 'anagrams/root'
6
+ require_relative 'anagrams/root'
7
+
8
+ module RubyAnagrams
9
+ # Namespace for the Ruby-Anagrams gem.
10
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ruby-anagrams
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Connor Lay
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-06-02 00:00:00.000000000 Z
11
+ date: 2015-06-09 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -76,6 +76,7 @@ files:
76
76
  - lib/anagrams/enumerable.rb
77
77
  - lib/anagrams/node.rb
78
78
  - lib/anagrams/root.rb
79
+ - lib/anagrams/string_to_symbol_array.rb
79
80
  - lib/anagrams/subtrees.rb
80
81
  - lib/ruby-anagrams.rb
81
82
  homepage: https://github.com/connorlay/ruby-anagrams