Ziu
Ziu

Reputation: 659

why does the array elements change after block?

I am trying to solve this problem

Given a sentence containing multiple words, find the frequency of a given word in that sentence.

Construct a method named 'find_frequency' which accepts two arguments 'sentence' and 'word', both of which are String objects.

Example: The method, given 'Ruby is The best language in the World' and 'the', should return 2 (comparison should be case-insensitive).

Hint: You can use the method Array#count to count the frequency of any element in the given array.

Since the comparison should be case-insensitive. I use these code to help:

word = "the"
word_set = []
word.size.times do |i|
  word[i] = word[i].upcase
  word_set << word
  word[i] = word[i].downcase
end

Inside the block every time after upcase method the word does change and does add to the word_set, however when the block finish the word_set just contain the the the What is the problem?

Upvotes: 0

Views: 79

Answers (4)

chad_
chad_

Reputation: 3819

You could do something like this:

class Array
  def group_and_count     
    self.map(&:downcase).each_with_object(Hash.new(0)){|k,h|h[k] += 1}
  end
end

Then when you want to find the frequency of a given word you could say:

> words = 'Here is a a a list OF OF words words WORDS'
> freq = words.split.group_and_count
> freq['a']
=> 3

Upvotes: 0

Stefan
Stefan

Reputation: 114188

I am still confused about that block code

The block runs 3 times with i = 0, 1, 2. Here's what happens:

                               #  word   word_set
word[0] = word[0].upcase       #  'The'  []
word_set << word               #  'The'  ['The']
word[0] = word[0].downcase     #  'the'  ['the']

word[1] = word[1].upcase       #  'tHe'  ['tHe']
word_set << word               #  'tHe'  ['tHe', 'tHe']
word[1] = word[1].downcase     #  'the'  ['the', 'the']

word[2] = word[2].upcase       #  'thE'  ['thE', 'thE']
word_set << word               #  'thE'  ['thE', 'thE', 'thE']
word[2] = word[2].downcase     #  'the'  ['the', 'the', 'the']

This is because you are modifying the very same string object. At the end, your array contains the same string instance three times.

You can avoid this by using dup to create a copy of your string, something like:

word = "the"
word_set = []
word.size.times do |i|
  new_word = word.dup
  new_word[i] = new_word[i].upcase
  word_set << new_word
end

word_set #=> ["The", "tHe", "thE"]

Note that you still have to add the, THe, tHE, ThE and THE to your array.

Upvotes: 2

Roland Mai
Roland Mai

Reputation: 31077

Well, word[i] = word[i].upcase is problematic, because you are setting it to upcase and downcase, the word will change over time. What you should have focused on is the Array#count method, which takes a block as a parameter.

Here is the gist of it:

def find_frequency sentence, word
  sentence.split(" ").count{|w| w == word }
end

To finish it off, complete the puzzle by taking into account case sensitivity of word and sentence

Upvotes: 1

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369478

You add the same string to the array over and over again. In the end of the loop, the array will contain the same string n times (where n ist the length of the string). So, you are changing the same string back and forth between uppercase and lowercase, but it's still just one string.

Upvotes: 1

Related Questions