Check if a string contains all the characters of another string in Ruby

Say I have a string, for example string= "aasmflathesorcerersnstonedksaottersapldrrysaahf" . If you haven’t noticed, you can find there the phrase "harry potter and the sorcerers stone" (minus a space).

I need to check if string contains all the elements of a string.

 string.include? ("sorcerer") #=> true string.include? ("harrypotterandtheasorcerersstone") #=> false, even though it contains all the letters to spell harrypotterandthesorcerersstone 

Include does not work for shuffled string.

How to check if a row contains all the elements of another row?

+8
string ruby
source share
4 answers

Array sets and intersections do not take into account repeated characters, but a histogram / frequency counter :

 require 'facets' s1 = "aasmflathesorcerersnstonedksaottersapldrrysaahf" s2 = "harrypotterandtheasorcerersstone" freq1 = s1.chars.frequency freq2 = s2.chars.frequency freq2.all? { |char2, count2| freq1[char2] >= count2 } #=> true 

Write your own Array#frequency if you do not want the facet to be dependent.

 class Array def frequency Hash.new(0).tap { |counts| each { |v| counts[v] += 1 } } end end 
+11
source share

I assume that if the string being checked is a "sorcerer", string should include, for example, three "r". If so, you can use the Array # difference method, which I suggested adding to the Ruby core.

 class Array def difference(other) h = other.each_with_object(Hash.new(0)) { |e,h| h[e] += 1 } reject { |e| h[e] > 0 && h[e] -= 1 } end end str = "aasmflathesorcerersnstonedksaottersapldrrysaahf" target = "sorcerer" target.chars.difference(str.chars).empty? #=> true target = "harrypotterandtheasorcerersstone" target.chars.difference(str.chars).empty? #=> true 

If the target characters should not only be in str , but should be in the same order, we could write:

 target = "sorcerer" r = Regexp.new "#{ target.chars.join "\.*" }" #=> /s.*o.*r.*c.*e.*r.*e.*r/ str =~ r #=> 2 (truthy) 

(or !!(str =~ r) #=> true )

 target = "harrypotterandtheasorcerersstone" r = Regexp.new "#{ target.chars.join "\.*" }" #=> /h.*a.*r.*r.*y* ... o.*n.*e/ str =~ r #=> nil 
+5
source share

Another, but not necessarily the best solution using sorted arrays of characters and substring:

Given your two lines ...

 subject = "aasmflathesorcerersnstonedksaottersapldrrysaahf" search = "harrypotterandthesorcerersstone" 

You can sort the subject line using .chars.sort.join ...

 subject = subject.chars.sort.join # => "aaaaaaacddeeeeeffhhkllmnnoooprrrrrrssssssstttty" 

Then create a list of substrings to search for:

 search = search.chars.group_by(&:itself).values.map(&:join) # => ["hh", "aa", "rrrrrr", "y", "p", "ooo", "tttt", "eeeee", "nn", "d", "sss", "c"] 

Alternatively, you can create the same set of substrings using this method

 search = search.chars.sort.join.scan(/((.)\2*)/).map(&:first) 

And then just check if each line of the search substring appears within the sorted topic:

 search.all? { |c| subject[c] } 
+2
source share
  • Create a 2-dimensional array from your string letters bank to associate the number of letters with each letter.

  • Create a 2-dimensional array from the Harry Potter string in the same way.

  • Go through both and make comparisons.

I have no experience with Ruby, but I would start doing this in the language that I know best, it is Java.

-one
source share

All Articles