i'm starting in ruby and i don't know why this is happening.
this is my code.
def buble_sort(a)
i = 0
print a.size()
while i < a.size() do
if a[i] > a[i+1] then
temp = a[i]
a[i] = temp
a[i+1] = a[i]
end
i = i + 1
end
return a
end
puts "Amount of elements in your array"
n = gets.chomp.to_i
a = []
n.times do |num|
puts "input your element #{num}"
a <<gets.chomp.to_i
end
puts a
a = buble_sort(a)
puts "Array sorted #{a}"
And the output give me this error:
4burbuja.rb:6:in >': comparison of Fixnum with nil failed (ArgumentError)
from burbuja.rb:6:inbuble_sort'
from burbuja.rb:24:in `'
I understand that you are learning ruby and want to implement your own bubble sort. a.sort is easy but doesn't teach you anything. I'm glad you are learning by doing! There is a flaw in your bubble sort method. You are incrementing i and using it as an index for your array on each iteration. It could take many iterations to complete, in the worst case it will take n**2 (n squared) iterations which will clearly be more than the elements in your array. However if your code worked as I expect you expected it to run it would only make one pass on the array.
This is a classic ruby bubble sort. (with your having the user fill the array from console)
Notice that we continue to process the ENTIRE array multiple times until we no longer need to swap any values.
def bubble_sort(array)
n = array.length
puts "Sorting your array of #{n} items"
loop do #will loop forever till we break
#When we go through the entire array
#and don't have to swap then the array
#is sorted
swapped = false
(n-1).times do |i|
print "*" #just to illustrate how many iterations occur
if array[i] > array[i+1]
array[i], array[i+1] = array[i+1], array[i] #swap these values, no pesky temp variable
swapped = true
end
end
break if not swapped #we are done exit the loop
end
array #return the sorted array
end
puts "Amount of elements in your array"
n = gets.chomp.to_i
a = []
n.times do |num|
puts "input your element #{num}"
a <<gets.chomp.to_i
end
puts a
a = bubble_sort(a)
puts "Array sorted #{a}"
Here is an example of it being run via console
Cyclops% ruby sort_test.rb
Amount of elements in your array
6
input your element 0
5465463
input your element 1
3421
input your element 2
432143
input your element 3
234123
input your element 4
645
input your element 5
1
5465463
3421
432143
234123
645
1
Sorting your array of 6 items
******************************
Array sorted [1, 645, 3421, 234123, 432143, 5465463]
Cyclops%
Related
I am doing some data migration, comparing tables between a legacy and a new database. I have a loop that raises exceptions when two arrays do not have the same size.
array1.zip(array2).each do |ar1, ar2|
# some code here
end
I want to know how to exit the loop when we reach the same size of the two arrays.
The loop breaks when reaches the last element of the first array zipped.
array1 = ['a', 'b', 'c', 'd']
array2 = ['x', 'y', 'z']
array1.zip(array2).each do |ar1, ar2|
puts "#{ar1} -- #{ar2}"
end
puts "-"*10
array2.zip(array1).each do |ar2, ar1|
puts "#{ar1} -- #{ar2}"
end
You could swap the variables if the first array is bigger:
array1, array2 = array2, array1 if array1.size > array2.size
array1.zip(array2).each do |ar1, ar2|
puts "#{ar1} -- #{ar2}"
end
If you just want to check if data are the same and don't want keep track of data origin.
[array1.size, array1.size].min.each do |i|
# code here referencing array1[i] and array2[i]
end
Given arrays:
a = %w[ 1 2 3 10 ]
b = %w[ 1 4 5 1 ]
c = %w[ 5 4 3 ]
If you want to compare two arrays for length:
a.length == b.length
# => true
a.length == c.length
# => false
If you want to compare that the elements in the arrays are of the same length and that the arrays are the same length:
def equal_size_elements(a, b)
return false unless a.length == b.length
a.zip(b).all? do |_a, _b|
_a.length == _b.length
end
end
Where that checks if all of the elements have different lengths because if they all match then it's good, otherwise not good. That method will halt iterating as soon as it finds a mismatch because at that point they can't all pass.
I found a solution, maybe there is better one than mine, I am just a beginner in ruby :
j = 0
array1.zip(array2).each do |ar1, ar2|
j += 1
break if [array1.size,array2.size].min == j
....
end
Just a bit better than your solution:
array1.zip(array2).each_with_index do |zipped, index|
break if index == [array1.size, array2.size].min
puts zipped.first
puts zipped.last
puts
end
Below is my quicksort code in ruby, and its working fine for array size like 20-25 but getting either stack level too deep error or its getting stuck for longer time.
I am guessing i am doing a trivial mistake but not able to figure out.
# This program is to do sorting using Quick sort.
require 'colorize'
class QuickSort
attr_accessor :array
def initialize(size)
puts "Generating Random numbers for your array".cyan
#array = (1..size.to_i).map do
rand(500) # Generating random numbers between 1 to 500.
end
# Boundary case
if #array.size == 1
puts "Your sorted array is"
p #array
return
end
puts "Array Before Sorting".yellow
p #array
#head = 0
#tail = #array.size-1
startSort(#array,#head,#tail) #Start the searching logic.
end
# Quicksort logic
def startSort(array,head,tail)
if head < tail
pivot = partitionArray(array,head,tail) # Calling the sorting logic
startSort(array,head,pivot-1)
startSort(array,pivot+1,#tail)
end
end
# This method is called to partition the array based on pivot.
def partitionArray(array,head,tail)
pivot_value = array[(head+tail)/2] # Choosing random pivot value.
# Run this partition step until head is equal to tail
while head <= tail
if array[head] < pivot_value
head += 1
elsif array[head] >= pivot_value
if array[tail] > pivot_value
tail -= 1
elsif array[tail] <= pivot_value
# Swapping head and tail values
temp = array[head]
array[head] = array[tail]
array[tail] = temp
# Moving each pointer forward from both the directions.
head += 1
tail -= 1
end
end
end
return head # Nothing but pivot
end
end
puts "Enter the size of Array"
#size = gets.chomp
# Checking if entry is a valid integer or not.
if #size.match(/^(\d)+$/)
#obj = QuickSort.new(#size)
puts "Array after sorting is ".green
p #obj.array
else
puts "Invalid Entry".red
end
Your implementation of quick sort algorithm is not correct. In a line:
startSort(array, pivot + 1, #tail)
you always call startSort method for pivot + 1 and array.size - 1 because #tail is an instance variable. It is assigned to #array.size - 1 only once and its value never changes. However, simply changing this line to
startSort(array, pivot + 1, tail)
is not enough to fix your code. With this change, it works fast even for large arrays but produces incorrect answer. This line should actually be:
startSort(array, pivot, tail).
With this change, it works fast for large arrays and sorts the array properly.
I have solved the problem using normal loops and now using hashes, however I am not confident I used the hashes as well as I could have. Here is my code:
# 1-100 whats duplicated
def whats_duplicated?(array)
temp = Hash.new
output = Hash.new
# Write the input array numbers to a hash table and count them
array.each do |element|
if temp[element] >= 1
temp[element] += 1
else
temp[element] = 1
end
end
# Another hash, of only the numbers who appeared 2 or more times
temp.each do |hash, count|
if count > 1
output[hash] = count
end
end
# Return our sorted and formatted list as a string for screen
output.sort.inspect
end
### Main
# array_1 is an array 1-100 with duplicate numbers
array_1 = []
for i in 0..99
array_1[i] = i+1
end
# seed 10 random indexes which will likely be duplicates
for i in 0..9
array_1[rand(0..99)] = rand(1..100)
end
# print to screen the duplicated numbers & their count
puts whats_duplicated?(array_1)
My question is really what to improve? This is a learning excercise for myself, I am practising some of the typical brain-teasers you may get in an interview and while I can do this easily using loops, I want to learn an efficient use of hashes. I re-did the problem using hashes hoping for efficiency but looking at my code I think it isn't the best it could be. Thanks to anyone who takes an interest in this!
The easiest way to find duplicates in ruby, is to group the elements, and then count how many are in each group:
def whats_duplicated?(array)
array.group_by { |x| x }.select { |_, xs| xs.length > 1 }.keys
end
whats_duplicated?([1,2,3,3,4,5,3,2])
# => [2, 3]
def whats_duplicated?(array)
array.each_with_object(Hash.new(0)) { |val, hsh| hsh[val] += 1 }.select { |k,v| v > 1 }.keys
end
I would do it this way:
def duplicates(array)
counts = Hash.new { |h,k| h[k] = 0 }
array.each do |number|
counts[number] += 1
end
counts.select { |k,v| v > 1 }.keys
end
array = [1,2,3,4,4,5,6,6,7,8,8,9]
puts duplicates(array)
# => [4,6,8]
Some comments about your code: The block if temp[element] == 1 seems not correct. I think that will fail if a number occurs three or more times in the array. You should at least fix it to:
if temp[element] # check if element exists in hash
temp[element] += 1 # if it does increment
else
temp[element] = 1 # otherwise init hash at that position with `1`
end
Furthermore I recommend not to use the for x in foo syntax. Use foo.each do |x| instead. Hint: I like to ask in interviews about the difference between both versions.
So I am trying to create a simple sorting program using the swapping method and I just cant get it to work properly. The code seems solid and it works up until it gets to artichoke. I've gone through and 'puts' the value of array during each iteration and pear swaps with apple, then swaps with orange, then swaps with peach and grapefruit, but when it gets to artichoke it refuses to swap like it should. It also doesn't seem like its an issue with it being the final item in the list because if I add, lets say, banana to the end it still stops at artichoke. Ultimately I want to nest the function inside an 'm.times do' function to continue the swapping until the entire list is sorted but for some reason when I put
m.times do
end
surrounding the 'n.times do' it creates another error. But I guess it doesn't even matter if I cant even get artichoke to swap with pear. Here is my code below (yes I am aware there is a .sort function, this is for learning purposes).
## Ignore this part, it is just a function I made and commented out to create
## your own list.
=begin
array = []
while true
puts "what item would you like to add to your list to be sorted?"
puts "press enter without entering an item to quit"
item = gets.chomp
break if item.empty?
array.push item
end
=end
##
array = ['pear' , 'apple' , 'orange' , 'peach' , 'grapefruit' , 'artichoke']
i = 0
m = array.length
n = m - 1
n.times do
if array.to_s[i] >= array.to_s[i+1]
swap = array[i]
array[i] = array[i+1]
array[i+1] = swap
end
i += 1
end
puts array
array = ['pear' , 'apple' , 'orange' , 'peach' , 'grapefruit' , 'artichoke']
m = array.length
n = m - 1
n.times do
i = 0
n.times do
if array[i] >= array[i+1]
temp = array[i]
array[i] = array[i+1]
array[i+1] = temp
end
i += 1
end
end
puts array
In this method of sorting, called "bubble sorting", you need nested loops. After just one run only the topmost element is guaranteed to be at its correct position. This is also known as infamous O(n*n) complexity of this poor algorithm. Btw. The inner loop can be shorther, like n-i times.
Fixed some mistakes:
array.to_s[i] is wrong because index has to be applied to array, not to_s method
... and its not necessary to call to_s since elements of this particular array already are strings
i = 0 had to be moved to the beggining of the outer loop
term "swap" refers to action, while variable is usually called "temp"
I think you mean to do array[i] >= array[i+1]
array.to_s will make a string out of your entire array and so you are comparing a character at a time of your stringified array instead of a word at a time as you seem to be intending to do.
So this code will count the total number of pairs of numbers whose difference is K. it is naive method and I need to optimize it. suggestions?
test = $stdin.readlines
input = test[0].split(" ")
numbers = test[1].split(" ")
N = input[0]
K = input[1]
count = 0
for i in numbers
current = i.to_i
numbers.shift
for j in numbers
difference = (j.to_i - current).abs
if (difference == K)
count += 1
end
end
end
puts count
Would have been nice for you to give some examples of input and output, but I think this is correct.
require 'set'
def count_diff(numbers, difference)
set = Set.new numbers
set.inject 0 do |count, num|
set.include?(num+difference) ? count+1 : count
end
end
difference = gets.split[1].to_i
numbers = gets.split.map { |num| num.to_i }
puts count_diff(numbers, difference)
Untested, hopefully actual Ruby code
Documentation for Set: http://www.ruby-doc.org/stdlib/libdoc/set/rdoc/classes/Set.html
require 'set'
numbers_set = Set.new
npairs = 0
numbers.each do |number|
if numbers_set.include?(number + K)
npairs += 1
end
if numbers_set.include?(number - K)
npairs += 1
end
numbers_set.add(number)
end
Someone deleted his post, or his post was deleted... He had the best solution, here it is :
test = $stdin.readlines
input = test[0].split(" ")
numbers = test[1].split(" ")
K = input[1]
count = 0
numbers.combination(2){|couple| couple.inject(:-).abs == K ? count++}
puts count
You don't even need N.
I do not know Ruby so I'll just give you the big idea:
Get the list
Keep a boolean array (call it arr), marking off numbers as true if the number exists in the list
Loop through the list and see if arr[num-K] and/or arr[num+K] is true where num is a number in your list
This uses up quite a bit of memory though so another method is to do the following:
Keep a hash map from an integer n to an integer count
Go through your list, adding num+K and num-K to the hash map, incrementing count accordingly
Go through your list and see if num is in the hash map. If it is, increment your counter by count