Bubble Sort an array of strings using index - ruby

Hello I am thoroughly confused on how to implement bubble sort in an array of strings. I need to write a method in which I swap index 1 and index 2 using an array. For something like swapper(["b", "c", "l"], 0, 1) I want this solution: ["c", "b", "l"]
Here's the code so far:
def swapper(arr, idx_1, idx_2)
sorted = false
while != sorted
sorted = true
(0...arr.length - 1).each do |i|
#idk how to compare idx_1 and idx_2 to swap
sorted = false
end
end

Something like this will work:
def swapper(arr, idx_1, idx_2)
arr[idx_1], arr[idx_2] = arr[idx_2], arr[idx_1]
return arr
end

Related

Creating a sort method using recursive method in Ruby (without using .sort)

I have tried to recreate the ".sort" function in Ruby, using the recursive method. However, all I get as the output is 'Nil' and I'm not sure why. Can anyone see what I'm doing wrong?
def sort arr
if arr.length > 0
result << arr.min
arr.delete(arr.min)
sort arr
else
new_array.length == 0
result
end
end
The problem with what you have is that you have a couple of unassigned variables result and new_array.
Here's an example of a custom sort method that uses partition with a recursive method. It takes the first element of your array and splits your array into two parts using partition into a group containing elements lesser and greater than this first element using recursion.
def sort(arr)
return [] if arr.length == 0
f_element = arr.shift
less, greater = arr.partition {|x| x < f_element }
sort(less) + [f_element] + sort(greater)
end
arr = "happiness".chars
print sort(arr)
#=> ["a", "e", "h", "i", "n", "p", "p", "s", "s"]

How do I transpose multiple arrays unless an array element is empty?

I have the following code:
[array1, array2, array3].transpose
I want to do something like this:
[array1, array2, array3].transpose unless array2[value] == ""
I want to transpose each array, but when the value for array2 that is being transposed is blank I want to skip to the next set of values altogether, ensuring that none of the arrays get transposed.
How can I handle that within Ruby 1.9.3?
Consider this :
arr1 = ["a", "b"]
arr2 = ["", "c"]
arr3 = ["d", "e"]
Now, as per your requirement,; you want those tranposed arrays where arr2 blank value is not present.
Use #reject to do that as:
[arr1, arr2, arr3].transpose.reject{ |x| x[1].empty? }
Here, x[1] corresponds to the second element in each transposed array; and it comes from arr2; so here, we rejected all those instances where "" was present in arr2.
Hope it helps
If you had large arrays, and memory were a concern, you could reduce the size of the array before transposing it. That's straightfoward. Here's one way (i being the row containing one or more instances of bad_obj):
def tr(arr, i, bad_obj)
bad_cols = []
arr[i].each_with_index {|e,i| bad_cols << i if e==bad_obj}
arr.map {|row| row.reject.with_index {|e,i| bad_cols.include?(i)}}.transpose
end
arr = [[1,2,3], [4,'',6], [7,8,9]]
tr(arr, 1, "") # => [[1,4,7], [3,6,9]]
construct an array bad_cols that contains the indices of the columns to be skipped.
remove the bad_cols columns from each row, then apply transpose.
Edit: replaced
bad_cols = arr[i].each_with_index.reduce([]) {|a,e| a << e.last if e.first==bad_obj; a}
with the first two lines of def tr(). Simpler is better.

Each_pair analog for array (zipping 2 arrays)

There is each_pair method allows getting pairs of hash on every loop iteration:
{ 1 => "a", 2 => "b" }.each_pair do |key, value|
# do something with #{key} and #{value}
end
How can index of current array element could be known on every loop iteration?
array.each do |element|
# what is element index in array?
end
There is a boring solution using some incrementing iterator. But that iterator
should be assigned before the loop and should be manually incremented on every
iteration. It's obviously boring.
It will be great if there is a some way to zip some array with 1.. array and
get array of tuples like ["b", "d", "e"] → [(1,"b"), (2,"d"), (3,"e")] and
than pattern matched each element of the pair in| |` statement.
So, finally, what I am looking for is some function f, that:
f(["a"]) do |index, element|
# index == 1, element == "a"
end
You can loop over an array and get the current index by using Enumerable::each_with_index
Correct me if I'm wrong, but I'm assuming that you want an array consisting of sub-arrays with the originall arrays index and value?
a= ["b", "d", "e"]
a.enum_with_index.map {|ind, val| [ind, val]
=> [[0, "b"], [1, "d"], [2, "e"]]

Reorder Ruby array based on the first element of each nested array

My goal is to convert a into b:
a = [["a","b"], ["d", "c"], ["a", "o"], ["d", "g"], ["c", "a"]]
b = [[["a","b"], ["a", "o"]], ["c", "a"], [["d", "c"], ["d", "g"]]
They are grouped by the first element in each nested array. So far I have:
def letter_frequency(c)
d = Hash.new(0)
c.each do |v|
d[v] += 1
end
d.each do |k, v|
end
end
def separate_arrays(arry)
arry2 = []
arry3 = []
big_arry = []
y = 0
while y < arry.length
arry2.push(arry[y][0])
arry3.push(arry[y][1])
y += 1
end
freq = letter_frequency(arry2)
front = arry.slice!(0..(freq["a"] - 1))
end
separate_arrays(a)
Not only does this seem like overkill, but there are now guarantees that "a" will be a legit Hash key, so the last part doesn't work. Thanks for any help.
You can try to do something like this:
a.group_by(&:first).values.map {|e| e.length > 1 ? e : e.flatten}
# => [[["a", "b"], ["a", "o"]], [["d", "c"], ["d", "g"]], ["c", "a"]]
I use the following methods:
Enumerable#group_by (by first element of an array, like in your question):
Returns a hash, which keys are evaluated result from the block, and
values are arrays of elements in enum corresponding to the key.
Hash#values:
Returns a new array populated with the values from hsh. See also Hash#keys.
Enumerable#map (required because you don't want to get nested array when there are only one match, like for c letter):
Returns a new array with the results of running block once for every element in enum.
Enumerable#flatten:
Returns a new array that is a one-dimensional flattening of this array
(recursively). That is, for every element that is an array, extract
its elements into the new array. If the optional level argument
determines the level of recursion to flatten

Check to see if an array is already sorted?

I know how to put an array in order, but in this case I just want to see if it is in order. An array of strings would be the easiest, I imagine, and answers on that front are appreciated, but an answer that includes the ability to check for order based on some arbitrary parameter is optimal.
Here's an example dataset. The name of:
[["a", 3],["b",53],["c",2]]
Where the elements are themselves arrays containing several elements, the first of which is a string. I want to see if the elements are in alphabetical order based on this string.
It looks like a generic abstraction, let's open Enumerable:
module Enumerable
def sorted?
each_cons(2).all? { |a, b| (a <=> b) <= 0 }
end
end
[["a", 3], ["b", 53],["c", 2]].sorted? #=> true
Notice that we have to write (a <=> b) <= 0 instead of a <= b because there are classes that support <=> but not the comparator operators (i.e. Array), since they do not include the module Comparable.
You also said you'd like to have the ability "to check for order based on some arbitrary parameter":
module Enumerable
def sorted_by?
each_cons(2).all? { |a, b| ((yield a) <=> (yield b)) <= 0 }
end
end
[["a", 3], ["b", 1], ["c", 2]].sorted_by? { |k, v| v } #=> false
Using lazy enumerables (Ruby >= 2.1), we can reuse Enumerable#sorted?:
module Enumerable
def sorted_by?(&block)
lazy.map(&block).sorted?
end
end
You can compare them two by two:
[["a", 3],["b",53],["c",2]].each_cons(2).all?{|p, n| (p <=> n) != 1} # => true
reduce can compare each element to the one before, and stop when it finds one out of order:
array.reduce{|prev,l| break unless l[0] >= prev[0]; l}
If it turns out the array isn't sorted, will your next action always be to sort it? For that use case (though of course depending on the number of times the array will already be sorted), you may not want to check whether it is sorted, but instead simply choose to always sort the array. Sorting an already sorted array is pretty efficient with many algorithms and merely checking whether an array is already sorted is not much less work, making checking + sorting more work than simply always sorting.
def ascending? (array)
yes = true
array.reduce { |l, r| break unless yes &= (l[0] <= r[0]); l }
yes
end
def descending? (array)
yes = true
array.reduce { |l, r| break unless yes &= (l[0] >= r[0]); l }
yes
end
Iterate over the objects and make sure each following element is >= the current element (or previous is <=, obviously) the current element.
For this to work efficiently you will want to sort during insertion.
If you are dealing with unique items, a SortedSet is also an option.
For clarification, if we patch array to allow for a sorted insertion, then we can keep the array in a sorted state:
class Array
def add_sorted(o)
size = self.size
if size == 0
self << o
elsif self.last < o
self << o
elsif self.first > o
self.insert(0, o)
else
# This portion can be improved by using a binary search instead of linear
self.each_with_index {|n, i| if n > o; self.insert(i, o); break; end}
end
end
end
a = []
12.times{a.add_sorted(Random.rand(10))}
p a # => [1, 1, 2, 2, 3, 4, 5, 5, 5, 5, 7]
or to use the built in sort:
class Array
def add_sorted2(o)
self << o
self.sort
end
end
or, if you are dealing with unique items:
require "set"
b = SortedSet.new
12.times{b << Random.rand(10)}
p b # => #<SortedSet: {1, 3, 4, 5, 6, 7, 8, 9}>
These are all way too hard. You don't have to sort, but you can use sort to check. Scrambled array below for demonstration purposes.
arr = [["b",3],["a",53],["c",2]]
arr.sort == arr # => false
p arr.sort # => [["a",53],["b",3],["c",2]]

Resources