Retrieving max element from SortedSet - ruby

I found SortedSet#max, but it seems to be O(N). For now I would do something like this:
s = SortedSet.new((1..100000).to_a.reverse)
where reverse is just to make sure.
min_element = nil; s.each { |x| min_element = x; break }
For maximum element, I would build another SortedSet with all values multiplied by -1 and do the same thing. Is there a more conventional way to do this?

Monkey patch SortedSet.
class SortedSet
def max
#keys[-1]
end
def min
#keys[0]
end
end
That's O(1).

Related

Efficient way to do addition on big array

I have an array with +20000 integer elements.
I want to create a new array where each element in the old array is added a modifying number. On a small sample array it would look like this:
old_array = [2,5,6,8]
modifying_number = 3
new_array = [5,8,9,11]
Is there any more efficient way than doing an iteration like this?
class Array
def addition_by(x)
collect { |n| n + x }
end
end
No. N iterations are the minimal complexity of this algorithm.
You can do it in place by modifying source array with collect!(if you for some reasons not need a source array). Complexity will be the same, additional big object will not created.
20k records is not much to worry about performance.
ary = Array.new(20000) { 1 }
ary.map! { |el| el + 1 }
would work totally fine.
I would just suggest to modify the initial array inplace instead of creating a new one (using method with bang), so it will definitely use less resources.
I guess it would mean implementing map in another way? This question deals with such a task. I've included benchmarks of the answers by #JörgWMittag and #uishra. Although it has to be said speed was not a requirement in the linked question so the answers cannot be criticised in that regard. I've also included #CarySwoveland's answer from this question.
require 'fruity'
require 'matrix'
class Array
#jörg_w_mittag
def new_map
return enum_for(__callee__) unless block_given?
inject([]) {|acc, el| acc << yield(el) }
end
#uishra
def my_map(&block)
result = []
each do |element|
result << block.call(element)
end
result
end
#cary_swoveland
def vec_map(k)
(Vector[*[k]*self.size] + Vector[*self]).to_a
end
end
arr = (1..30000).to_a
k = 3
10.times do
compare do
core_map { ar = arr.dup; ar.map { |n| n + k } }
jörg_w_mittag { ar = arr.dup; ar.new_map { |n| n + k } }
uishra { ar = arr.dup; ar.my_map { |n| n + k } }
cary_swoveland { ar = arr.dup; ar.vec_map k }
end
puts
end
A summary of the results/output:
Results on five occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than jörg_w_mittag by 2x ± 1.0
#jörg_w_mittag is similar to uishra
#uishra is similar to cary_swoveland
Results on two occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than jörg_w_mittag by 2x ± 0.1
#jörg_w_mittag is similar to uishra
#uishra is similar to cary_swoveland
Results on three occasions
#Running each test once. Test will take about 1 second.
#core_map is faster than uishra by 2x ± 1.0
#uishra is similar to jörg_w_mittag
#jörg_w_mittag is similar to cary_swoveland
require 'matrix'
class Array
def vec_map(k)
(Vector[*[k]*self.size] + Vector[*self]).to_a
end
end
[1,2,3].vec_map 4
#=> [5, 6, 7]

What are some nice ways to reverse a nested hash?

Suppose we have
b = {"b"=>"c"}
By doing b.invertwe can easily obtain the result of
{"c"=>"b"}
Thats when I thought of trying something pretty cool. Suppose we have
a = {"a"=>{"b"=>"c"}}
Whats a fairly efficient way to make this {{"c"=>"b"}=>"a"} (Here we reverse the most inner hash and work our way out)
Of course it would be best to extend this to n amount of hashes within each other. I've been looking for some other questions similar but haven't found any.
Thanks.
This can be accomplished with a recursive method for inverting the keys of the hash (and values, if desired). For example:
hsh = {{"c"=>"b"}=>"a"}
def recursive_invert(hsh)
hsh.each_with_object({}) do |(k, v), inverted_hsh|
if k.is_a? Hash
k = recursive_invert(k)
end
inverted_hsh[v] = k
end
end
recursive_invert(hsh) # {"a"=>{"b"=>"c"}}
Here's A recursive solution that will work in both directions.
def deep_invert(h)
h.each_with_object({}) do |(k,v),obj|
k = deep_invert(k) if k.is_a?(Hash)
v = deep_invert(v) if v.is_a?(Hash)
obj[v] = k
end
end
Example:
a = {"a"=>{"b"=>"c"}}
deep_invert(a)
#=> {{"c"=>"b"}=>"a"}
deep_invert(deep_invert(a)) == a
#=> true

How to write my own max function

I know that there is a max function from the Enumerable library in Ruby.
However, I'm trying to figure out how to write my own max method in which the largest number in an array is figured out.
How do I do that? I'm really at loss because when I Google it, all I keep getting is the max function itself.
Any help/advice would be helpful!
Another naive approach is -
list = [3,4,2,5,6,7,8,2,5,1,4,4,6]
def maximum(list)
len = list.size - 1
maximum = list[0]
for i in 1..len
if maximum < list[i]
maximum = list[i]
end
end
maximum
end
puts maximum(list)
# >> 8
Here is the graphical explanation(taken from this link) -
You have 2 approaches: Enumerable#each (imperative) or Enumerable#reduce (usually functional, depends on how you use it). I prefer functional solutions, so I'd write:
module Enumerable
def my_max
reduce { |current_max, x| x > current_max ? x : current_max }
end
end

Is this a faithful rendition of the selection sort algorithm?

I've been reading an elementary book about sort algorithms. To get my head around it, I tried to write a simple program to implement the algorithm.
EDIT: I had omitted an important line that was in a previous version - see comment below.
This is my selection sort:
class SelectionSorter
attr_reader :sorted
def initialize(list)
#unsorted = list
#sorted = []
end
def select(list)
smallest = list.first
index = 0
list.each_with_index do |e,i|
if e < smallest
smallest = e
index = i
end
end
#sorted << list.delete_at(index)
end
def sort
#unsorted.length.times { self.select(#unsorted) }
end
end
Here's a test:
require 'minitest/autorun'
require_relative 'sort'
class SelectionSortTest < MiniTest::Test
describe SelectionSorter do
it 'sorts a randomly generated list' do
list = (1..20).map { rand(100-1) + 1 }
sorted_list = list.sort
sorter = SelectionSorter.new(list)
sorter.sort
sorter.sorted.must_equal sorted_list
end
end
end
I'd love comments, particularly around whether this is actually a faithful implementation of the algorithm.
EDIT 2:
OK - here's my in-place code. This is the sort of thing I wanted to avoid, as it feels nastily procedural, with nested loops. However, I think it's a faithful implementation.
class SelectionSorter
def sort(list)
sorted_boundary = (0..(list.length)-1)
sorted_boundary.each do |sorted_index|
smallest_index = sorted_index
smallest_value = list[smallest_index]
comparison = sorted_index + 1
(comparison..(list.length-1)).each do |next_index|
if list[next_index] < smallest_value
smallest_index = next_index
smallest_value = list[smallest_index]
end
end
unless sorted_index == smallest_index
list[smallest_index] = list[sorted_index]
list[sorted_index] = smallest_value
end
end
list
end
end
I'd love to do this in a more recursive fashion, with less stored state, and without nested loops. Any suggestions?
Try adding smallest = e immediately after index = i, so you are keeping a running tally of the smallest value found so far.
I'd also note that selection sort is usually implemented in-place, i.e., scan locations 1-N of your list for the min and then swap it with the first element, then repeat the process with elements 2-N, 3-N, etc. There's no need for a second array or the expense of removing elements from the middle of an array.
I don't know the selection sort algorithm, but I can tell that your code does not do sorting. In this part:
list.each_with_index do |e,i|
if e < smallest
index = i
end
end
you end up having as index the index of the last element of #unsorted that is smaller than the first element of #unsorted (If there is no such element, then index is 0). Then, by:
#sorted << list.delete_at(index)
you take that element from #unsorted, and push it into #sorted. And you repeat this process. That does not give you sort.

Error accessing an array's value by it's index?

Trying to sum up all the numbers in an array. Example 10 + 20 + 30 should be 60.
def sum *arr
i=0
total=0
while i <= arr.count
total += arr[i]
i+=1
end
total
end
puts sum(10,20,30)
Why am I getting this error. This code looks like it should work to me. What am I doing wrong? Why wont it let me access the array value by it's index?
p8.rb:23:in `+': nil can't be coerced into Fixnum (TypeError)
from p8.rb:23:in `sum'
from p8.rb:29:in `<main>'
Change
while i <= arr.count
to
while i < arr.count
arr[arr.count] is always out of bounds.
Fyi a shorter way to write sum is:
def sum *arr
arr.inject(:+)
end
Matt's answer gives you the canonical Ruby way to sum, using inject. But if you're not ready to learn inject, at least save yourself the trouble of manually keeping track of array indexes (where your actual problem lies!) by using #each to iterate through the array like so:
def sum *arr
total = 0
arr.each do |x|
total += x
end
total
end
puts sum(10,20,30) # => 60
Matt's answer is both slick and correct, but you hit the error because ruby zero indexes arrays. So if you changed the count condition
while i <= arr.count - 1
your error would go away

Resources