ruby-anagrams 0.0.1 → 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
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