Attempting to redact multiple words


#1

How would I be able to do this without the text being doubled? I’ve been at it for about an hour and a half and I have no idea how to get rid of this.

puts "What text will you redact from?"
text = gets.chomp
words = text.downcase!.split(" ")
puts words

puts "What will you redact?"
redact = gets.chomp
redacted_words = redact.downcase!.split(" ")
puts redacted_words

words.each do |word|
redacted_words.each do |redacted|
  if word == redacted
    print "REDACTED "
  else  
    print word + " "
  end
end  
end

#2

You don’t need to do anything at all to accomplish that. Feed it back in with a new word.

…But if you were to “fix” what you’re doing, you would check each word and determine whether it should be redacted. And after that, you would do it, or not.
Or really any series of events you prefer. If you can do it manually you can probably describe it too.


#3

What do you mean by feed it back in with a new word? And I’m trying to check each word to see if it should be redacted, it works fine when only one word needs to be redacted. I’m really confused by your reply :confounded:

Edit: What do you mean by “it”? And how am I not checking each work to see if it should be redacted, then redacting words that should be afterward?


#4

You can redact one word. Then send the result back in with a new word.

redact('a b c', 'a') -> 'REDACTED b c'
redact('REDACTED b c', 'c') -> 'REDACTED b REDACTED'

Or, to stay closer to what you’re trying to write, you KNOW that you shouldn’t add something for each word you check. Instead you should check all the words, and if any match, then you replace it, otherwise you don’t.
Thinking about what actions should happen doesn’t involve ruby at all! Try doing the redaction process manually with a piece of paper, or in your head, or marbles. Watch what you do. Your program should be doing the same.


#5

“Check all the words”:

words.each do |word|
redacted_words.each do |redacted|

“If any match, then replace it”:

if word == redacted
    print "REDACTED "

“Otherwise you don’t”:

else  
    print word + " "

I’m not really sure what you’re trying to tell me. I get the teaching method of trying to get people to come to the right conclusion on their own, but telling me to do what I’m already trying to seems needlessly obtuse.


#6

You’d have to replace it after checking all words.

It’s not an action to repeat for each word. It’s done once, and only after you have figured out whether to do it, which you can only know after comparing to all the words

And I feel like I’m pointing out the obvious, that you full well already have everything you need to reason about it
I don’t believe you would insist on doing it once for each word if you did it manually. You’d compare to each word, and then either replace it or not.


#7

It may not make any difference, but to my mind it seems simpler to let the redacted_words form the outer loop, then search the text for that word, and redact as needed. You will iterate the entire text body only as many times as you have words in the redacted list, once all the way through for each one.


#8

But am I not checking all of the words? .each creates an array with each word from words when used on words, and does the same for redacted_words and redacted. Then the if checks each word and redacted.

I don’t know what else you would do if it was done manually. In one sentence, you say you wouldn’t do it for each word if it was done manually, but then in the next you say you would. What’s obvious to you is not necessarily obvious to me, and I’m sorry to say it but your comments are only making me more confused.


#9

No that would make multiple passes over the text, because it’s being done in a loop.
And no, it makes no difference


#10

You have an action which adds one of: REDACTED, the original word

You have this in a loop, causing it to be done multiple times

It should be done once, it therefore needs to be moved out of your loop.

Problem: something should be done once and is inside a loop
-> put it outside the loop


#11

As for obvious-ness

Since it is about the order and number of times that actions are being made, it’s the same as every-day reasoning.

For example, if you set a table for four persons, you wouldn’t give each person four knives.

I absolutely realize that it may not be obvious in this particular moment. But I am saying that if you completely ignore all you know about programming and viewed it as just actions… Then you’d see it for what it is, and you would find it obvious, because we humans do this kind of thing all the time.
And, that you indeed should ignore ruby and programming until you’ve figured out what exactly should happen. Because ruby is only there so that you can describe something. It’s not there to limit or control your thinking.
And, from there is where my suggestion to carry it out manually comes. Because that makes you think through it. It gives you something to observe - it’s the kind of reasoning that you do nearly automatically.

If your code ends up doing something other than what you mean, then that gives you opportunity to add prints in the code which write out what is being done. You can compare to what you would be doing. They should probably match exactly, the same steps should be carried out.


#12

I’m not sure if I’m understanding, but if you mean to move the if then that just breaks the entire thing. I’m sure it doesn’t actually have to do with .split and .downcase!, but I get errors saying they’re undefined methods. It happens for .split if the code is like this:

puts "What text will you redact from?"
text = gets.chomp
words = text.downcase!.split(" ")
puts words

puts "What will you redact?"
redact = gets.chomp
redacted_words = redact.downcase!.split(" ")
puts redacted_words

words.each do |word|
end
redacted_words.each do |redacted|
end  

if word == redacted
  print "REDACTED "
else  
  print word + " "
end

And .downcase! if the code is like this(which is the only way I can think of to get around this):

puts "What text will you redact from?"
text = gets.chomp
text_down = text.downcase!
words = text_down.split(" ")
puts words

puts "What will you redact?"
redact = gets.chomp
redact_down = redact.downcase!
redacted_words = redact_down.split(" ")
puts redacted_words

words.each do |word|
end
redacted_words.each do |redacted|
end  

if word == redacted
  print "REDACTED "
else  
  print word + " "
end

I don’t know what’s being repeated. When you set a table, it’s plain how many knives you’re putting down. When the code is plain(to me), it repeats something but I don’t understand what’s being repeated. What should happen is that the words that the user says should be replaced with REDACTED should get replaced, and the other words should be printed normally. It’s good to think things through manually, but if I’m writing code, I will have to actually write it at some point and that means thinking about how I would accomplish whatever task I’m trying to accomplish.

I’ve already added puts to show what redacted words and words contain, I don’t know where else they would be since the rest of the code already prints things.


#13

A different matter altogether, but sure:

The methods ending with bang (!) usually change the original. (note that a bang is not an operator, it’s part of the method name, nothing else)
You should probably not use them at all, unless that’s specifically what you need.

They may sometimes return nil rather than a string. nil doesn’t have string methods, it’s not a string.
The way you tell that they might return nil is by reading their documentation, frankly one can’t use methods/functions without first finding out what they do.

Rather than:

text.downcase!.split

do:

text.downcase.split

The non-bang methods return their results. Which is exactly what you rely on when you write another dot and another method name, because that’s operating on the result


#14

It just does the same thing, but with the bang-less versions :no_mouth:


#15

Well, it was definitely a bug, one that only happens when you set things up in ways that cause those methods to return nil instead of strings


#16

But why wouldn’t it return a string? The way it’s set up, it will just take what the user inputs and makes any uppercase letters lowercase.


#17

That’s how the non-bang methods behave, yes.
The bang versions do something slightly different, that’s why they have different names


#18

But they’re not behaving that way, they’re giving me the same errors the versions with bangs do, just without the bang.


#19

A way that you pretty much can’t do this mistake, is if you make a new method for the purpose of checking whether a word should be redacted

So it would accept one word, and the words which are not allowed, return a boolean

You’d then use that method to determine whether to redact or not. Note that this eliminates a loop, the loop where you duplicate your text.


#20

I don’t remember how to make a method. The whole reason why I’m going through the Ruby courses again is because I haven’t touched Ruby in about a year. So sure, while it says I’ve finished all the courses, I don’t remember most of what I learned.