1

I want to make a word unscarambler in ruby. say if I have a words in array

 words = ["foo","ofo"]

how can I compare this to another string like "oof" and returning true value

styvane
  • 59,869
  • 19
  • 150
  • 156
  • 1
    Please describe in more detail. What are you comparing? What would happen if the array was `["foo", "boo"]`? How about `["foo", "ugh", "bam"]`? Your title refers to two strings, but question talks about an array and a string. What is it you are trying to do? – Amadan Apr 27 '15 at 03:36
  • Im sorry it's an array of strings. so if i type/input a string like "oof" the program will prints "available results are "foo","ofo" to console, otherwise it prints " no results available " – Muhammad_Sigit_Dude Apr 27 '15 at 03:51
  • 1
    Muhammad, please clarify by editing your question rather than elaborating in comments. Are you saying you want to return the elements of `words` that are anagrams of a given string (e.g. `'ofo'``)? You should clarify whether it is to be case-sensitive. – Cary Swoveland Apr 27 '15 at 03:57
  • thanks Cary, yes it is case-sensitive – Muhammad_Sigit_Dude Apr 27 '15 at 04:03
  • Muhammad, I am disappointed that you have not made an effort to clarify your question. You may have got what you wanted from the answers, but you should consider that many (possibly many, many) others may read your question in future. Don't you think you have an obligation to them to make it clear and complete? (Downvote and vote to close are not mine.) – Cary Swoveland Apr 27 '15 at 04:50

2 Answers2

2

This can be done as follows.

words = ["foo", "ofo", "goo"]
target = "foo"
target_size = target.size
  #=> 3 
target_sorted = target.each_char.sort
  #=> ["f", "o", "o"] 

words.select { |w| anagram?(target_size, target_sorted, w) }
  #=> ["foo", "ofo"] 

The typical way anagram? is written is:

def anagram?(target_size, target_sorted, w)
  return false unless w.size == target_size
  w.each_char.sort == target_sorted
end

However, I've wondered it might be faster to:

  • Step through the characters of target
  • Search for the index i of a matching character in w
  • If a match is found, delete w[i]
  • if no match is found (i #=> nil), return false
  • return true if false is not returned earlier

This can be implemented thus:

def anagram?(target_size, target, w)
  return false unless target.size == w.size
  wcpy = w.dup
  target.each_char do |c|
    i = wcpy.index(c)
    return false unless i
    wcpy[i] = ''
  end
  true
end

words.select { |w| anagram?(target_size, target, w) }
  #=> ["foo", "ofo"]

I'll have to benchmark the two one day.

We could also write:

def anagram?(w1, w2)
  return false unless w1.size == w2.size
  w1.chars.difference(w2.chars).empty?
end

The helper Array#difference is defined here.

Cary Swoveland
  • 106,649
  • 6
  • 63
  • 100
  • thanks a lot, i try to use this approach, its a bit complex to me, my program solved with your code "target.each_char.sort" .by the way its not really an anagram because i just want to check if a 'scrambled' word include in a dictionary (txt file). Anyway i nevermind the downvote :) – Muhammad_Sigit_Dude Apr 27 '15 at 05:04
1

If all the strings in the array are permutations of each other then:

words = ["foo", "ofo"]
str = "foo"

words[0].split("").sort == str.split("").sort