Swap adjacent elements in array - ruby

I am trying to build a method in Ruby that will take in a string that has been split into an array of letters and then iterate through the array, swapping the element at index n with that at index n+1. The method will then join the new array into a string and push it to another array.
Here is an example of what I am looking to do:
string = "teh"
some_method(string)
some ruby magic here
array << new_string
end
Expected output:
["eth", "the"]
This is for a spell checker program I am writing for school. The method will check if letters in a misspelled word are swapped by checking to see if the output array elements are in the dictionary. If they are, it will return the word with that is most likely the correct word. I haven't had any luck finding articles or documentation on how to build such a method in ruby or on an existing method to do this. I've been tinkering with building this method for awhile now but my code isn't behaving anything like what I need. Thanks in advance!

As #Sergio advised, you want to use parallel assignment for this:
def reverse_em(str)
(0...str.size-1).map do |i|
s = str.dup
s[i], s[i+1] = s[i+1], s[i]
s
end
end
candidates = reverse_em "alogrithm"
#=> ["laogrithm", "aolgrithm", "algorithm", "alorgithm",
# "alogirthm", "alogrtihm", "alogrihtm", "alogritmh"]
dictionary_check(candidates)
#=> algorithm
# al·go·rithm
# noun \ˈal-gə-ˌri-thəm\
# a set of steps that are followed in order to solve a
# mathematical problem or to complete a computer process

Without splitting it into arrays then joining to new arrays (because that doesn't seem necessary):
def some_method(string)
swapped_strings = []
(0...string.size-1).each do |i|
temp_string = string.dup
temp_string[i], temp_string[i+1] = temp_string[i+1], temp_string[i]
swapped_strings << temp_string
end
swapped_strings
end

Related

Ruby: Understanding .to_enum better

I have been reading this:
https://docs.ruby-lang.org/en/2.4.0/Enumerator.html
I am trying to understand why someone would use .to_enum, I mean how is that different than just an array? I see :scan was passed into it, but what other arguments can you pass into it?
Why not just use .scan in the case below? Any advice on how to understand .to_enum better?
"Hello, world!".scan(/\w+/) #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan, /\w+/).to_a #=> ["Hello", "world"]
"Hello, world!".to_enum(:scan).each(/\w+/).to_a #=> ["Hello", "world"]
Arrays are, necessarily, constructs that are in memory. An array with a a lot of entries takes up a lot of memory.
To put this in context, here's an example, finding all the "palindromic" numbers between 1 and 1,000,000:
# Create a large array of the numbers to search through
numbers = (1..1000000).to_a
# Filter to find palindromes
numbers.select do |i|
is = i.to_s
is == is.reverse
end
Even though there's only 1998 such numbers, the entire array of a million needs to be created, then sifted through, then kept around until garbage collected.
An enumerator doesn't necessarily take up any memory at all, not in a consequential way. This is way more efficient:
# Uses an enumerator instead
numbers = (1..1000000).to_enum
# Filtering code looks identical, but behaves differently
numbers.select do |i|
is = i.to_s
is == is.reverse
end
You can even take this a step further by making a custom Enumerator:
palindromes = Enumerator.new do |y|
1000000.times do |i|
is = (i + 1).to_s
y << i if (is == is.reverse)
end
end
This one doesn't even bother with filtering, it just emits only palindromic numbers.
Enumerators can also do other things like be infinite in length, whereas arrays are necessarily finite. An infinite enumerator can be useful when you want to filter and take the first N matching entries, like in this case:
# Open-ended range, new in Ruby 2.6. Don't call .to_a on this!
numbers = (1..).to_enum
numbers.lazy.select do |i|
is = i.to_s
is == is.reverse
end.take(1000).to_a
Using .lazy here means it does the select, then filters through take with each entry until the take method is happy. If you remove the lazy it will try and evaluate each stage of this to completion, which on an infinite enumerator never happens.

Is there a better way?: iterating over an array in ruby

I'm working on a mini project for a summer class. I'd like some feedback on the code I have written, especially part 3.
Here's the question:
Create an array called numbers containing the integers 1 - 10 and assign it to a variable.
Create an empty array called even_numbers.
Create a method that iterates over the array. Place all even numbers in the array even_numbers.
Print the array even_numbers.
Here's my code, so far:
numbers = [1,2,3,4,5,6,7,8,9,10]
print numbers[3]
even_numbers.empty?
def even_numbers
numbers.sort!
end
Rather than doing explicit iteration, the best way is likely Array#select thus:
even_numbers = numbers.select { |n| n.even? }
which will run the block given on each element in the array numbers and produce an array containing all elements for which the block returned true.
or an alternative solution following the convention of your problem:
def get_even_numbers(array)
even_num = []
array.each do |n|
even_num << n if n.even?
end
even_num
end
and of course going for the select method is always preferred.

Nested Data Structures: Why is my Hash turning into an Array of an Array?

For an assignment I am working on, I'm trying to sort words in a piece of text by frequency of words in the text. I have a function that almost accomplishes what I'd like to do but not quite. Below is my code:
require 'pry'
def top_words(words)
word_count = Hash.new(0)
words = words.split(" ")
words.each { |word| word_count[word] += 1 }
word_count = word_count.sort_by do |words, frequencies|
frequencies
end
binding.pry
word_count.reverse!
word_count.each { |word, frequencies| puts word + " " + frequencies.to_s }
end
words = "1st RULE: You do not talk about FIGHT CLUB.
2nd RULE: You DO NOT talk about FIGHT CLUB.
3rd RULE: If someone says 'stop' or goes limp, taps out the fight is over.
4th RULE: Only two guys to a fight.
5th RULE: One fight at a time.
6th RULE: No shirts, no shoes.
7th RULE: Fights will go on as long as they have to.
8th RULE: If this is your first night at FIGHT CLUB, you HAVE to fight."
For some reason, the sort_by method above my binding.pry is changing the structure of my Hash into an array of an array. Why?
What I'd like to do is to sort the words within a hash and then grab the top three words from the Hash. I've yet to figure out how to do this but I'm pretty sure I can do this once I've sorted the array of an array problem.
Now, I suppose I could grab them using .each and array[0].each { |stuff| puts stuff[0] + stuff[1] } but I don't think that is the most efficient way. Any suggestions?
For some reason, the sort_by method above my binding.pry is changing the structure of my Hash into an array of an array. Why?
Explanation is below :
sort_by { |obj| block } → array method give always array.
The current implementation of sort_by generates an array of tuples containing the original collection element and the mapped value. This makes sort_by fairly expensive when the keysets are simple.
Now in your case word_count is a Hash object, thus sort_by is giving you like - [[key1,val],[key2,val2],..]. This is the reason you are getting array of array.
What I'd like to do is to sort the words within a hash and then grab the top three words from the Hash. I've yet to figure out how to do this but I'm pretty sure I can do this once I've sorted the array of an array problem.
Yes, possible.
sorted_array_of_array = word_count.sort_by do |words, frequencies| frequencies }
top_3_hash = Hash[ sorted_array_of_array.last(3) ]
I would write the code as below :
def top_words(words)
# splitting the string words on single white space to create word array.
words = words.split(" ")
# creating a hash, which will have key as word and value is the number of times,
# that word occurred in a sentence.
word_count = words.each_with_object(Hash.new(0)) { |word,hash| hash[word] += 1 }
# sorting the hash, to get a descending order sorted array of array
sorted_array_of_array = word_count.sort_by { |words, frequencies| frequencies }
# top 3 word/frequency is taken from the sorted list. Now reading them from last
# to show the output as first top,second top and so on..
sorted_array_of_array.last(3).reverse_each do |word, frequencies|
puts "#{word} has #{frequencies}"
end
end

Why is the method deleting the element inside my array?

I'm trying to create my own .sort method as an exercise in a ruby book, using recursion, and for some reason they haven't taught me the spaceship operator yet. My code works to get the smallest value - apple - and puts it in the sorted array, and it even repeats using the recursion, and resets the array to repeat the process to add the second smallest word. The problem is for some reason it removes the smallest word -apple- and I can't figure out why. I know where I think - in the else myArray.length == 1 statement when I pop the element off the array, but why is it removing from the sortedArray too?
sortedArray ends up with value apple, then when it does recursion it SHOULD be sortedArray = ['apple', 'banana' …] but it removes apple, then it removes banana etc… until I end up with sortedArray = ['quincy']
I have tried moving my arrays to multiple places, and I've tried adding to the sortedWords array in multiple places but it is always deleting or resetting the sortedWords array.
It looks like I'm really close since I've got the alphabetizing working. How do I get it to add all the items to the sortedWords array?
ArrayofWords = ['cat', 'dog', 'bat', 'elephant', 'apple', 'banana', 'quincy', 'boo']
# Why is it deleting, or replacing my sortedWords array? If you run this code you will notice that the sortedWords array
# is giving me the smallest word in the array, but then I add the recursive part, and somehow the previous smallestword
#gets deleted... but I have never in any part of my code say delete or replace the sorted array...
def sortTheArray myArray
unsortedWords = []
sortedWords = []
smallestValue = ''
while myArray.length != 0
if myArray.first < myArray.last
unsortedWords.push(myArray.last)
myArray.pop
elsif myArray.first > myArray.last
unsortedWords.push(myArray.first)
myArray.delete_at(0)
else myArray.length == 1
sortedWords.push(myArray.first)
myArray.pop # This is my problem area I think???
end # if else
#puts 'sorted words'
#puts sortedWords
#puts 'unsortedWords'
#puts unsortedWords
end # while
puts 'sorted words'
puts sortedWords
puts 'unsortedWords'
puts unsortedWords
myArray = unsortedWords
while myArray.length > 0
sortTheArray myArray
end #while
end # sortTheArray
sortTheArray ArrayofWords
most of those puts's are not necessary, I was just trying to figure out where the problem was.
You've got numerous problems with your code. For example, you seem to want to accumulate sorted words across invocations of this method, but you reinitialize sorted_words to [] at the start of the method block.
I would suggest first trying to express your recursive solution in English as simply as possible and then seek to implement it.
For example, the following is an approach which seems to be in line with what you are trying to do:
def sorted_array(array)
lowest_value prepended to the sorted_value of the array with the lowest_value removed
end
I'm sharing the above because it appears that you're new to Ruby and just implementing the above in an idiomatic fashion will be a good challenge.

Is this the best way to grab common elements from a Hash of arrays?

I'm trying to get a common element from a group of arrays in Ruby. Normally, you can use the
& operator to compare two arrays, which returns elements that are present or common in both arrays. This is all good, except when you're trying to get common elements from more than two arrays. However, I want to get common elements from an unknown, dynamic number of arrays, which are stored in a hash.
I had to resort to using the eval() method in ruby, which executes a string as actual code. Here's the function I wrote:
def get_common_elements_for_hash_of_arrays(hash) # get an array of common elements contained in a hash of arrays, for every array in the hash.
# ["1","2","3"] & ["2","4","5"] & ["2","5","6"] # => ["2"]
# eval("[\"1\",\"2\",\"3\"] & [\"2\",\"4\",\"5\"] & [\"2\",\"5\",\"6\"]") # => ["2"]
eval_string_array = Array.new # an array to store strings of Arrays, ie: "[\"2\",\"5\",\"6\"]", which we will join with & to get all common elements
hash.each do |key, array|
eval_string_array << array.inspect
end
eval_string = eval_string_array.join(" & ") # create eval string delimited with a & so we can get common values
return eval(eval_string)
end
example_hash = {:item_0 => ["1","2","3"], :item_1 => ["2","4","5"], :item_2 => ["2","5","6"] }
puts get_common_elements_for_hash_of_arrays(example_hash) # => 2
This works and is great, but I'm wondering...eval, really? Is this the best way to do it? Are there even any other ways to accomplish this(besides a recursive function, of course). If anyone has any suggestions, I'm all ears.
Otherwise, Feel free to use this code if you need to grab a common item or element from a group or hash of arrays, this code can also easily be adapted to search an array of arrays.
Behold the power of inject! ;)
[[1,2,3],[1,3,5],[1,5,6]].inject(&:&)
=> [1]
As Jordan mentioned, if your version of Ruby lacks support for &-notation, just use
inject{|acc,elem| acc & elem}
Can't you just do a comparison of the first two, take the result and compare it to the next one etc? That seems to meet your criteria.
Why not do this:
def get_common_elements_for_hash_of_arrays(hash)
ret = nil
hash.each do |key, array|
if ret.nil? then
ret = array
else
ret = array & ret
end
end
ret = Array.new if ret.nil? # give back empty array if passed empty hash
return ret
end

Resources