user3125373
user3125373

Reputation: 3

Algorithm to detect if a word in an array matches a given string + regex? RUBY

I'm trying to build a simple algorithm to detect if a word in an array matches a given string (in this case, g) uniquely--as in, only 1 appearance of the characters in g, AND an unlimited amount of appearances of the vowels--aeiouy.

g = "bs"


arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']

for y in arr
  return y if y.include? { |z| /[aeiouy]/ =~ z } and y.include? { |z|/[ #{g} ]/ =~ z }

end

Expected output:

base
bees
# all others either have more than 1 b or s, or contain other consonants.

Getting this error:

include?': wrong number of arguments (0 for 1) (ArgumentError)

I think there could be better ways of doing this, using .find or .any? perhaps?

Upvotes: 0

Views: 148

Answers (4)

tuxdna
tuxdna

Reputation: 8487

Based on the sample in the question, I presume two cases:

  1. The order of consonants on g = "bs" should remain same in the target.
  2. The order of consonants doesn't matter. So it g = "bs" will also match a the strings "sb", "sabe", "sob", "boose" etc.

For case 1:

You can first remove all vowels from target words in the arr array. Then match it with the pattern in g, and select only those words which match.

g = "bs"
arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']
arr.map{ |x| [x, x.gsub(/[aeiou]/,'')] }.select{ |x| x[1] == g }.map{|x| x[0]}
# ["base", "bees"]

For case2, simply sort the source string characters and target string characters before a match:

g = "bs"
arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']
v1 = arr.map{ |x| [x, x.gsub(/[aeiou]/,'')] }.select{ |x| x[1] == g }.map{|x| x[0]}
p v1 
# ["base", "bees"]

arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss', "sb", "sabe", "sob", "boose"]
v2 = arr.map{ |x| [x, x.gsub(/[aeiou]/,'')] }.select{ |x| x[1].split("").sort == g.split("").sort }.map{|x| x[0]}
p v2
# ["base", "bees", "sb", "sabe", "sob", "boose"]

Depending on the amount of data in arr you can keep the intermediate values pre-processed for faster results.

Upvotes: 0

sawa
sawa

Reputation: 168239

If the order of the characters should be taken into account:

g = "bs"
arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']
arr.select{|w| w.tr("aeiouy", "") == g}

If the order of the characters should not be taken into account:

g = "bs"
g = g.each_char.sort
arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']
arr.select{|w| w.tr("aeiouy", "").each_char.sort == g}

Upvotes: 1

bjhaid
bjhaid

Reputation: 9782

This is what you want:

2.0.0p247 :122 > ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss'].select do |x|  
  x.match /^(?>b)[^bs]*(?>s)[^bs]*\b/
end
=> ["base", "bees"]

EDIT

Matching unlimited amount of vowels aeiouy

['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss'].select do |x|
  x.match /^(?>b)[aeiouy]*(?>s)[aeiouy]*\b/
end
=> ["base", "bees"]

Upvotes: 0

andrykonchin
andrykonchin

Reputation: 2582

Use Array#grep method (core lib) and String#count (codelib)

We look for words contained both characters (b and s) only once.

g = ["b", "s"]    
arr = ['base', 'vase', 'race', 'bees', 'bass', 'sabb', 'babss']

arr.grep(/[aeiouy]/).select { |w| g.all? { |s| w.count(s) == 1  } }

Upvotes: 2

Related Questions