1

I'd like to point out I tried quite extensively to find a solution for this and the closest I got was this. However I couldn't see how I could use map to solve my issue here. I'm brand new to Ruby so please bear that in mind.

Here's some code I'm playing with (simplified):

def base_word input
    input_char_array = input.split('') # split string to array of chars
    @file.split("\n").each do |dict_word|
        input_text = input_char_array
        dict_word.split('').each do |char|
            if input_text.include? char.downcase
                input_text.slice!(input_text.index(char))
            end
        end
    end
end

I need to reset the value of input_text back to the original value of input_char_array after each cycle, but from what I gather since Ruby is reference-based, the modifications I make with the line input_text.slice!(input_text.index(char)) are reflected back in the original reference, and I end up assigning input_text to an empty array fairly quickly as a result.

How do I mitigate that? As mentioned I've tried to use .map but maybe I haven't fully wrapped my head around how I ought to go about it.

3
  • What are you expecting for output? You're slicing the text, but it doesn't look like it's being printed or returned anywhere. Commented Nov 9, 2015 at 17:48
  • #map won't get around the issue in your question, but it could help with output. I'll update my answer with #map when you include some info about your expected output. Commented Nov 9, 2015 at 18:06
  • The reason I didn't include anything about that is because I don't really believe it's relevant--my point was that making modifications of any kind to input text results in the original value of input_char_array also being changed, as such negating what I was trying to achieve in 'resetting' input-text Commented Nov 10, 2015 at 9:15

2 Answers 2

1

You can get an independent reference by cloning the array. This, obviously, has some RAM usage implications.

input_text = input_char_array.dup
Sign up to request clarification or add additional context in comments.

4 Comments

Would it make more sense to use #slice instead of #slice! here, and avoid #duping altogether?
Well, then slice will do some copying.
Right, just thinking it's one less method call. Either is valid; wasn't sure if there might be obvious benefit to either approach.
I've up-voted this because I found it useful and it helped with my issue--would have been nice to have seen more explanation/possible alternatives/implications though!
1

The Short and Quite Frankly Not Very Good Answer

Using slice! overwrites the variable in place, equivalent to

input_text = input_text.slice # etc.

If you use plain old slice instead, it won't overwrite input_text.

The Longer and Quite Frankly Much Better Answer

In Ruby, code nested four levels deep is often a smell. Let's refactor, and avoid the need to reset a loop at all.

Instead of splitting the file by newline, we'll use Ruby's built-in file handling module to read through the lines. Memoizing it (the ||= operator) may prevent it from reloading the file each time it's referenced, if we're running this more than once.

def dictionary
  @dict ||= File.open('/path/to/dictionary')
end

We could also immediately make all the words lowercase when we open the file, since every character is downcased individually in the original example.

def downcased_dictionary
  @dict ||= File.open('/path/to/dictionary').each(&:downcase)
end

Next, we'll use Ruby's built-in file and string functions, including #each_char, to do the comparisons and output the results. We don't need to convert any inputs into Arrays (at all!), because #include? works on strings, and #each_char iterates over the characters of a string.

We'll decompose the string-splitting into its own method, so the loop logic and string logic can be understood more clearly.

Lastly, by using #slice instead of #slice!, we don't overwrite input_text and entirely avoid the need to reset the variable later.

def base_word(input)
  input_text = input.to_s # Coerce in case it's not a string
  # Read through each line in the dictionary
  dictionary.each do |word|
    word.each_char {|char| slice_base_word(input_text, char) }
  end
end

def slice_base_word(input, char)
  input.slice(input.index(char)) if input.include?(char)
end

2 Comments

Thanks, Matt. I've up-voted this because it's a really detailed and well-considered answer. I'm still reading through it at the moment--but as a beginner to Ruby this is very helpful because it's introduced a few ideas I might otherwise have taken a while to uncover.
I appreciate you're lacking context to the problem, but this doesn't fully help with the issue I had at hand, so I'll mark Sergio's as the correct answer. Again, thanks for showing me some ideas that will be handy in future though.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.