Wali Chaudhary
Wali Chaudhary

Reputation: 177

Why does is the index of the array repeatedly be printed out to be 2?

I'm working on this function:

It's supposed to take in an array and match it with a given word to see if that word can be formed with the given array of strings.

I added the two commented lines because I wanted to see how the for-loop works.

def canformword(arr,word)
  arrword = word.chars
  arrleft = arr
  flag = true
  for i in 0...arrword.size
    ch = arrword[i]
    # puts arrword[i]
    if !arrleft.include?(ch)
      flag = false
      break
    else
      ind = arrleft.index(ch)
      # puts ind
      arrleft.delete_at(ind)
    end
  end
  if flag
    puts 'can form word'
  else
    puts 'can not form word'
  end
end

canformword(['y','b','z','e','a','u','t'], 'beauty')
canformword(['r','o','u','g','h'], 'tough')

When I uncomment those two lines, the following is the output:

Why does the output print out the index 2 repeatedly? I would think that it would print out the index of each letter in my arrleft array rather than repeatedly spitting out 2!

I understand the 1 it prints out, because that's the index of b, but the rest is weird to me.

b
1
e
2
a
2
u
2
t
2
y
0
can form word
t
can not form word

Upvotes: 1

Views: 77

Answers (4)

Eric Duminil
Eric Duminil

Reputation: 54223

Problem

If you want do delete index 2 and 3 from an array, you need to delete them in decreasing order, becausing deleting index 2 would modify index of 3:

array = %w(a b c d e)
array.delete_at(3)
array.delete_at(2)
p array
#=> ["a", "b", "e"]

or

array = %w(a b c d e)
array.delete_at(2)
array.delete_at(2)
p array
#=> ["a", "b", "e"]

Solution

For your code, you just need to replace

arrleft.delete_at(ind)

with

arrleft[ind] = nil

Alternative

Since you take the numbers of characters into account, here's a modified version of a previous answer :

class Array
  def count_by
    each_with_object(Hash.new(0)) { |e, h| h[e] += 1 }
  end

  def subset_of?(superset)
    superset_counts = superset.count_by
    count_by.all? { |k, count| superset_counts[k] >= count }
  end
end

def can_form_word?(chars, word)
  word.chars.subset_of?(chars)
end

p can_form_word?(['y','b','z','e','a','u','t'], 'beauty')
#=> true
p can_form_word?(['y','b','z','e','u','t'], 'beauty')
#=> false
p can_form_word?(['a', 'c', 'e', 'p', 't', 'b', 'l'], 'acceptable')
#=> false
p ('acceptable'.chars - ['a', 'c', 'e', 'p', 't', 'b', 'l']).empty?
#=> true

Upvotes: 1

Nafaa Boutefer
Nafaa Boutefer

Reputation: 2359

hear a better implementation that

def can_form_word?(chars_array, word)
   (word.chars - chars_array).empty?
end

that's all.

here another implementation the Ruby way. Because your code is like C. I've been writing Ruby code for more than three years now, and I never used for loops.

def canformword(chars,word)
    word.each_char do |char|
       puts char
       if !chars.include?(char)
         return false # or puts "Can't form word"
       end
    end
    true # or puts "Can form word"
end

Upvotes: 3

Ursus
Ursus

Reputation: 30056

You obtain 2 several times because you are deleting elements from the array. In that case you delete the second element every time so the next character, in the next iteration, take the index 2 again.

Upvotes: 2

KOUSIK MANDAL
KOUSIK MANDAL

Reputation: 2052

this is because you are deleting the character at position ind(arrleft.delete_at(ind)); so each time array characters are shifting one cell left. Now as all your letters 'e','a','u','t','y' are placed ordered way so it is showing 2,2,2,2 continuously. Now look at 'y'; it is at position 0 ; so 0 is printed at end.

So the issue is because you are deleting the characters at position 'ind'.

So, to achieve this you can just do one thing ; do not delete the characters when found rather replace it by some numeric value like '0'.

Upvotes: 2

Related Questions