optimize this ruby code - ruby

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

Related

How do I get a numerical value for all the characters that are repeated in a certain string?

def num_repeats(string)
letters = string.chars
idx = 0
n = 1
arr = []
lettercount = 0
while idx < letters.length
lettercount = 0
while n < letters.length
if letters[idx] == letters[n]
lettercount = 1
end
n+=1
end
if lettercount > 0
arr.push(idx)
end
idx += 1
end
return arr.length
end
puts(num_repeats("abdbccc"))
# == 2 since 2 letters are repeated across the string of characters
I keep getting zero, although as i see it if a number is repeated the value of numbercount should shift from zero to one and then allow some value to get pushed into the array where I later get the length of said array to determine the number of repeated characters. Is there an issue with my loops?
UPDATE
If you really want to use the same kind of code and algorithm to do that, then here are the problems of it :
In your second while loop the variable n is supposed to start from idx+1, considering you are trying to pick up an index and then find whether the character at that index is repeated somewhere after the index.
But even if you fix that you will get 3 for abdbccc. That kinda shows that your algorithm is wrong. When there are more than 2 occurrences of a repeated character, just like the process I said in the above para, you do that for every such character except for the last one, without checking whether the character had already been detected for repetition. Illustration :
str = 'aaa'
When idx = 0, you get str[idx] == str[n=1], adds it to the result.
When idx = 1, you get str[idx] == str[n=2], adds it to the result.
Now you counted a twice for repetition. I think you can fix that alone.
I think you are just trying to do the same as this (assumes you need to check lower case letters only) :
str = "abdbccc"
('a'..'z').count { |x| str.count(x) > 1 }
# => 2
Or if you need to check the number of repeated characters for any character :
str = "12233aabc"
str.chars.group_by(&:to_s).count do |k, v|
v.size > 1
end
# => 3
It's Ruby we are talking about. It's not really a good idea to write code like that in Ruby, I mean you are using a lot of while loops and manually tracking down their counters, while in Ruby you usually do not have to deal with those, considering all the convenient, less error-prone and shorter alternatives Ruby provides. I think you have a C like background, I recommend that you learn more of Ruby and Ruby way of doing things.
Didn't understood what you were trying to do, maybe you could use a hash to assist:
def num_repeats(string)
letters = string.chars
counter_hash = Hash.new(0)
letters.each { |l| counter_hash[l] += 1 }
counter_hash
end
You have this inner loop
while n < letters.length
if letters[idx] == letters[n]
lettercount = 1
end
n+=1
But nowhere are you resetting n, so after this loop has scanned once, it will skip past every subsequent time
You can mostly fix that by setting n to idx + 1 here
while idx < letters.length
lettercount = 0
n = idx + 1
while n < letters.length
You still will get a result of 3 because you are not detecting that c has already been counted
You can fix this final problem with a couple more tweaks
def num_repeats(string)
letters = string.chars
idx = 0
arr = []
lettercount = 0
while idx < letters.length
lettercount = 0
n = idx + 1 # <== start looking after idx char
while n < letters.length
if letters[idx] == letters[n]
lettercount += 1 # <== incrementing here
end
n+=1
end
if lettercount == 1 # <== check for exactly one
arr.push(idx)
end
idx += 1
end
return arr.length
end
This works because now lettercount == 2 for the first c so the duplicate is not counted until you get to the second c where lettercount == 1
This is still considered a poor solution as it has O(n**2) complexity. There are solutions - for example using Hash which are O(n)

Highest Prime Number

I am trying to find the highest prime number for a given integer. I can get the first portion of the code to work, but the part where I check to see if the factors are prime doesn't work. I don't get any errors, but the output (puts) I receive is blank, so I'm thinking a nil is being outputted. What's wrong with my code?
def highestprime num
i = 1
counter = 0
count = -1
factors = []
primes = []
while (i < num/2) #checks for all factors of number
i += 1
if (num%i == 0)
factors.push(i) #adds all factors to the end factors array
end
end
while (counter < factors.length) #goes through whole array
counter += 1
count += 1
while (i < factors[count]) #tests for particular index in array
i += 1
if (factors[count]%i == 0 and i != factors[count]) #if factor is divisible by a number, it is not prime, so break
break
elsif (factors[count]%i != 0 and i != factors[count]) #if it is not divisibe, then keep iterating
next
elsif (i == factors[count]) #if the end has been reached, then add to primes array
primes.push i
end
end
end
puts primes.pop #print the biggest(last) prime number
end
The first loop pushes some of the values of i into factors; when that loop is done, i is at least as big as every value in factors. The nested while loop, which is the only place anything can get pushed onto primes, only runs as long as i is less than some value in factors, which we just established never happens.
I see you are reusing the iterator variable i between loops, but I do not see where you reset it back to 1.
Maybe that?
You should check out the prime library. You can rewrite the entire thing in a few lines:
require 'prime'
def highestprime num
Prime.reverse_each(num) { |p| return p }
end
puts highestprime(10)

Merging two sorted arrays - why does this NOT work?

I am learning ruby and was given the following assignment:
given two sorted arrays like the following we must merge them into one sorted array.
array_1 = [5,8,9,11]
array_2 = [4,6,7,10]
merge(array_1, array_2)
=> [4,5,6,7,8,9,10,11]
Given this brief description, implement the merge method that takes two arrays and returns
the properly sorted array containing the items from each array.
I wrote this answer:
def merge(arr1, arr2)
i = 0
k = 0
merged_arr = []
until k = arr2.count
while arr1[i] <= arr2[k]
merged_arr.push(arr1[i])
i += 1
end
merged_arr.push(arr2[k])
k += 1
end
merged_arr
end
My instructor sent out a solution, which I understand, however I don't understand why my answer does NOT work. Can someone please explain the faulty logic? Thank you!
Here is the (correct) solution:
def merge(array_1, array_2)
i = 0
k = 0
merged_array = []
while i < array_1.count
while k < array_2.count && array_1[i] > array_2[k]
merged_array << array_2[k]
k += 1
end
merged_array << array_1[i]
i += 1
end
print merged_array.inspect
end
k = arr2.count assigns the value of arr2.count to k and evaluates to k, so until k = arr2.count is never executed.
you also need to consider the unequal length of arr1 and arr2, your instructor's solution was only right if arr1.length >= arr2.length, but if arr1.length < arr2.length, then the elements from the extra length was lost in the solution.

Prime factoring returns nil when fed primes

I made a method that generates prime factors. Whatever composite number I push to it, it gives the prime factors. However, if I push a prime number into it, it wouldn't return 1 and the number itself. Instead, it would return 1 and some prime number smaller than the number pushed into the method.
I decided to shove an if statement that would cut the process short if the number pushed into turns out to be prime. Here's the code:
def get_prime_factors(number)
prime_factors = []
i = 0
primes = primes_gen(number)
if primes.include?(number)
return "Already a prime!"
end
original_number = number
while primes[i] <= original_number / 2
if number % primes[i] == 0
prime_factors << primes[i]
number = number / primes[i]
else
i = i + 1
end
if number == 1
return prime_factors
end
end
end
I fed 101 to the method and the method returned nil. This method calls the primes_gen method, which returns an array containing all primes smaller than the input value. Here it is:
def primes_gen(limit)
primes = []
i = 0
while i <= limit
primes << i if isprime?(i)
i = i + 1
end
primes.delete(0)
primes.delete(1)
return primes
end
I know there ought to be a more finessed way to fix the. If anyone wants to recommend a direction for me to explore as far as that goes, I'd be very grateful.
EDIT: Changed line 4 of the primes_gen() method to include a <= operator instead of a < operator.
Try changing primes = primes_gen(number) to primes = primes_gen(number+1) in first function and see if it works. Or try changing the i < limit condition to i <= limit in the second function.
Also, why are you deleting the 0th and 1st element in primes_gen method? Is it because of values you get for 0, 1? In which case, you can initialize with i=2.

How do I generate the first n prime numbers?

I am learning Ruby and doing some math stuff. One of the things I want to do is generate prime numbers.
I want to generate the first ten prime numbers and the first ten only. I have no problem testing a number to see if it is a prime number or not, but was wondering what the best way is to do generate these numbers?
I am using the following method to determine if the number is prime:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
end
In Ruby 1.9 there is a Prime class you can use to generate prime numbers, or to test if a number is prime:
require 'prime'
Prime.take(10) #=> [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Prime.take_while {|p| p < 10 } #=> [2, 3, 5, 7]
Prime.prime?(19) #=> true
Prime implements the each method and includes the Enumerable module, so you can do all sorts of fun stuff like filtering, mapping, and so on.
If you'd like to do it yourself, then something like this could work:
class Integer < Numeric
def is_prime?
return false if self <= 1
2.upto(Math.sqrt(self).to_i) do |x|
return false if self%x == 0
end
true
end
def next_prime
n = self+1
n = n + 1 until n.is_prime?
n
end
end
Now to get the first 10 primes:
e = Enumerator.new do |y|
n = 2
loop do
y << n
n = n.next_prime
end
end
primes = e.take 10
require 'prime'
Prime.first(10) # => [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
Check out Sieve of Eratosthenes. This is not Ruby specific but it is an algorithm to generate prime numbers. The idea behind this algorithm is that you have a list/array of numbers say
2..1000
You grab the first number, 2. Go through the list and eliminate everything that is divisible by 2. You will be left with everything that is not divisible by 2 other than 2 itself (e.g. [2,3,5,7,9,11...999]
Go to the next number, 3. And again, eliminate everything that you can divide by 3. Keep going until you reach the last number and you will get an array of prime numbers. Hope that helps.
http://en.wikipedia.org/wiki/Sieve_of_Eratosthenes
People already mentioned the Prime class, which definitely would be the way to go. Someone also showed you how to use an Enumerator and I wanted to contribute a version using a Fiber (it uses your Integer#is_prime? method):
primes = Fiber.new do
Fiber.yield 2
value = 3
loop do
Fiber.yield value if value.is_prime?
value += 2
end
end
10.times { p primes.resume }
# First 10 Prime Numbers
number = 2
count = 1
while count < 10
j = 2
while j <= number
break if number%j == 0
j += 1
end
if j == number
puts number
count += 1
end
number += 1
end
Implemented the Sieve of Eratosthene (more or less)
def primes(size)
arr=(0..size).to_a
arr[0]=nil
arr[1]=nil
max=size
(size/2+1).times do |n|
if(arr[n]!=nil) then
cnt=2*n
while cnt <= max do
arr[cnt]=nil
cnt+=n
end
end
end
arr.compact!
end
Moreover here is a one-liner I like a lot
def primes_c a
p=[];(2..a).each{|n| p.any?{|l|n%l==0}?nil:p.push(n)};p
end
Of course those will find the primes in the first n numbers, not the first n primes, but I think an adaptation won't require much effort.
Here is a way to generate the prime numbers up to a "max" argument from scratch, without using Prime or Math. Let me know what you think.
def prime_test max
primes = []
(1..max).each {|num|
if
(2..num-1).all? {|denom| num%denom >0}
then
primes.push(num)
end
}
puts primes
end
prime_test #enter max
I think this may be an expensive solution for very large max numbers but seems to work well otherwise:
def multiples array
target = array.shift
array.map{|item| item if target % item == 0}.compact
end
def prime? number
reversed_range_array = *(2..number).reverse_each
multiples_of_number = multiples(reversed_range_array)
multiples_of_number.size == 0 ? true : false
end
def primes_in_range max_number
range_array = *(2..max_number)
range_array.map{|number| number if prime?(number)}.compact
end
class Numeric
def prime?
return self == 2 if self % 2 == 0
(3..Math.sqrt(self)).step(2) do |x|
return false if self % x == 0
end
true
end
end
With this, now 3.prime? returns true, and 6.prime? returns false.
Without going to the efforts to implement the sieve algorithm, time can still be saved quickly by only verifying divisibility until the square root, and skipping the odd numbers. Then, iterate through the numbers, checking for primeness.
Remember: human time > machine time.
I did this for a coding kata and used the Sieve of Eratosthenes.
puts "Up to which number should I look for prime numbers?"
number = $stdin.gets.chomp
n = number.to_i
array = (1..n).to_a
i = 0
while array[i]**2 < n
i = i + 1
array = array.select do |element|
element % array[i] != 0 || element / array[i] == 1
end
end
puts array.drop(1)
Ruby: Print N prime Numbers
http://mishra-vishal.blogspot.in/2013/07/include-math-def-printnprimenumbernoofp.html
include Math
def print_n_prime_number(no_of_primes=nil)
no_of_primes = 100 if no_of_primes.nil?
puts "1 \n2"
count = 1
number = 3
while count < no_of_primes
sq_rt_of_num = Math.sqrt(number)
number_divisible_by = 2
while number_divisible_by <= sq_rt_of_num
break if(number % number_divisible_by == 0)
number_divisible_by = number_divisible_by + 1
end
if number_divisible_by > sq_rt_of_num
puts number
count = count+1
end
number = number + 2
end
end
print_n_prime_number
Not related at all with the question itself, but FYI:
if someone doesn't want to keep generating prime numbers again and again (a.k.a. greedy resource saver)
or maybe you already know that you must to work with subsequent prime numbers in some way
other unknown and wonderful cases
Try with this snippet:
require 'prime'
for p in Prime::Generator23.new
# `p` brings subsequent prime numbers until the end of the days (or until your computer explodes)
# so here put your fabulous code
break if #.. I don't know, I suppose in some moment it should stop the loop
end
fp
If you need it, you also could use another more complex generators as Prime::TrialDivisionGenerator or Prime::EratosthenesGenerator. More info
Here's a super compact method that generates an array of primes with a single line of code.
def get_prime(up_to)
(2..up_to).select { |num| (2...num).all? { |div| (num % div).positive? } }
end
def get_prime(number)
(2..number).each do |no|
if (2..no-1).all? {|num| no % num > 0}
puts no
end
end
end
get_prime(100)

Resources