i have a project of a game, in it i need to impress the letter selected if the letter selected is present in the secret word, but when i try to catch the index of the select letter, like "a", in the secret word "programador, the code returns me all the index of the word "programador" not only the index where the letter "a" is present.
palavra_secreta = "programador"
letra_procurada = "a"
total_encontrado = palavra_secreta.count letra_procurada
palavra_secreta_array = palavra_secreta.split("")
puts palavra_secreta_array.each_with_index.select { |letra_procurada, index|
total_encontrado >= 1
}.map { |pair| pair[1] }
this code is returning me: 0 1 2 3 4 5 6 7 8 9 10
CodePudding user response:
In your code, total_encontrado
is 2
, which is greater than or equal to 1
. As a result, the condition you give to #select
is always true, so it selects every character with its index. You then map that to just the indices.
Instead, you likely want to select only the letters that match letra_procurada
.
palavra_secreta = "programador"
letra_procurada = "a"
total_encontrado = palavra_secreta.count letra_procurada
palavra_secreta_array = palavra_secreta.split("")
puts palavra_secreta_array.each_with_index.select { |letra, index|
letra_procurada == letra
}.map { |pair| pair[1] }
You could also use #filter_map
(Ruby 2.7 and later) to simplify this.
palavra_secreta = "programador"
letra_procurada = "a"
total_encontrado = palavra_secreta.count letra_procurada
palavra_secreta_array = palavra_secreta.split("")
puts palavra_secreta_array.each_with_index.filter_map { |letra, index|
index if letra_procurada == letra
}
CodePudding user response:
The condition inside your select
clause will be true for every index, since it only checks the total_encontrado
variable and that value will not change in each iteration.
puts palavra_secreta_array
.each_with_index
.select { |letra_procurada, index| total_encontrado >= 1 }
# ^^^^^^^^^^^^^^^^^^^^^
.map { |pair| pair[1] }
What you want is to select the indexes that match the guessed character, so your condition could do that instead:
puts palavra_secreta_array
.each_with_index
.select { |letra, index| letra == letra_procurada }
.map { |pair| pair[1] }
Note that I had to change the name of the first parameter to the select
block. You had re-used letra_procurada
there, but that would have the effect of shadowing the actual letra_procurada
variable. Remember that select
is calling the block for each element in the array and selecting only the elements for which the that block returns true, so the first parameter to the block is the element from the array and, if you shadow or ignore it, you'll have no idea what you're dealing with inside the block.
You can also slim this down a bit more and skip the split
in favor of using String#each_char
:
puts palavra_secrata
.each_char
.with_index
.select { |c, _| c == letra_procurada }
.map(&:last)
CodePudding user response:
When dealing with problems where an array of indices of a collection or string whose corresponding elements satisfy a particular condition is to be returned, it is often convenient to work with an array of indices [0,1,..,n]
. For example, if one wanted to return an array of indices of elements of the array arr = [3,2,6,5,4]
that are odd numbers, one might write one of the following1:
arr.each_index.select { |i| arr[i].odd? }
(0..arr.size-1).select { |i| arr[i].odd? }
arr.size.times.select { |i| arr[i].odd? }
All return [0, 3]
.
For the present problem, involving a string, we could use either of the last two approaches above:
(0..palavra_secreta.size-1).select { |i| palavra_secreta[i] == letra_procurada }
palavra_secreta.size.times.select { |i| palavra_secreta[i] == letra_procurada }
Both return [5, 7]
.
1. For #2 one could of course write (0...arr.size)...
. I personally avoid the use of three-dot ranges, when possible, as I find mixing two- and three-dot ranges can spawn bugs.