Sum of positive elements in linked list - ruby

I need to make program, but i can't finish it and get into mess with methods.
The aim is to find the sum of all positive of elements and add it in the end. I am just started teach classes and methods.
How can I make the sum of all positive elements in my final array?
Here is my code:
class Node
attr_accessor :value, :next_node
def initialize val,next_in_line
#value = val
#next_nodex = next_in_line
puts "Initialized a Node with value: " + value.to_s
end
end
class LinkedList
def initialize val
#head = Node.new(val,nil)
end
def add(value)
current = #head
while current.next_node != nil
current = current.next_node
end
current.next_node = Node.new(value,nil)
self
end
def delete(val)
current = #head
if current.value == val
#head = #head.next_node
else
current = #head
while (current != nil) && (current.next_node != nil) && ((current.next_node).value != val)
current = current.next_node
end
if (current != nil) && (current.next_node != nil)
current.next_node = (current.next_node).next_node
end
end
end
def display
current = #head
full_list = []
while current.next_node != nil
full_list += [current.value.to_s]
current = current.next_node
end
full_list += [current.value.to_s]
puts full_list.join(" ")
end
def sum
end
end
puts "\n"
list = [*-99..99].shuffle
ll = LinkedList.new(list[0])
(1..9).each do |i|
ll.add(list[i])
end
puts "\nDo you want item to add? '1' - yes '0' - no"
adding = gets.to_i
puts "\n"
if adding == 1
ll.add(list[10])
end
puts "\nDisplaying Linked List:"
ll.display
puts "\nDo you want to delete item? '1' - yes '0' - no"
deleting = gets.to_i
if deleting == 1
puts "Type in and delete item and then display the linked list:"
deleteInt = gets.to_i
ll.delete(deleteInt)
end
puts ll.display
puts "\nThe sum of all positive elements"
ll.sum

Firstly, You have mistype in Node.initialize method - #next_nodex should be #next_node i think. Secondly, don't use puts 2 times: puts ll.display at the end. To add in array preferably use << symbol.
Another thing, i can't see any concept difference between display and sum methods, except one condition. According to this, it should be like:
def sum
current = #head
sum = 0
while current.next_node != nil
sum += current.value if current.value > 0
current = current.next_node
end
sum += current.value if current.value > 0
sum
end
or with dry:
def full_list
current = #head
full_list = []
while current.next_node != nil
full_list << current.value
current = current.next_node
end
full_list << current.value
full_list
end
def display
puts full_list.join(' ')
end
def sum
full_list.keep_if { |x| x > 0 }.reduce(:+)
end
All code

Related

Iterating over loops in ruby?

I am new to ruby. I am trying to create a letter counter. my intended output was supposed to be [2,"I"] but I keep getting [3,"D]. Any help in understanding where I went wrong would be so helpful, thank you.
class LetterCounter
def initialize(text)
#text = text
end
def calculate_most_common()
counter = Hash.new(1)
most_common = nil
most_common_count = 1
#text.chars.each do |char|
next unless is_letter?(char)
counter[char] = (counter[char] || 1) + 1
if counter[char] > most_common_count
most_common = char
most_common_count += counter[char]
end
end
return [most_common_count, most_common]
end
private
def is_letter?(letter)
return letter =~ /[a-z]/i
end
end
counter = LetterCounter.new("Digital Punk")
p counter.calculate_most_common
# Intended output:
# [2, "i"]
Try:
class LetterCounter
def initialize(text)
#text = text
end
def calculate_most_common()
arr=#text.scan(/[a-z]/i)
arr.each_with_object(Hash.new(0)) { |n,h| h[n] += 1 }.max_by(&:last)
end
end
counter = LetterCounter.new("Digital Punk")
p counter.calculate_most_common
Prints:
["i", 2]
If you want to fix yours, try:
class LetterCounter
def initialize(text)
#text = text
end
def calculate_most_common()
counter = Hash.new(0)
most_common = nil
most_common_count = 0
#text.chars.each do |char|
next unless is_letter?(char)
counter[char] += 1
if counter[char]>most_common_count
most_common=char
most_common_count=counter[char]
end
end
return [most_common_count, most_common]
end
private
def is_letter?(letter)
return letter =~ /[a-z]/i
end
end
counter = LetterCounter.new("Digital Punk")
p counter.calculate_most_common
class LetterCounter
def initialize(text)
#text = text
end
def calculate_most_common()
counter = Hash.new(0) # wrong initialization in your code
most_common = nil
most_common_count = 0
#text.chars.each do |char|
next unless is_letter?(char)
counter[char] = (counter[char] || 1) + 1
puts "#{char} #{counter[char]}"
if counter[char] > most_common_count
puts "most common: #{most_common_count} #{char} #{counter[char]}"
most_common = char
most_common_count = counter[char] # error in your code
end
end
return [most_common_count, most_common]
end
private
def is_letter?(letter)
return letter =~ /[a-z]/i
end
end
counter = LetterCounter.new("Digital Punk")
p counter.calculate_most_common
The initial counters are at 1. These should be 0 since you are incrementing inside your loop anyways.
On the First Iteration -
Hash counter[char] is being initialized to 1 ( From Hash.new(1) ),
Then counter[char] is increased to 1 on first loop and the most_common_count is also increased by 1.
Which leads to D having value 3.
since most_common_count is already at 3 - the loop would no longer go into the if condition - as other characters would reach only 2 ( 1 from Hash.new and 1 from counter[char] +1 )
The if condition is > most_common_count and not >= - hence even if i reaches 3 - condition would not execute.
Hence the output [3, 'D']
Try this instead :
class LetterCounter
def initialize(text)
#text = text
end
def calculate_most_common()
counter = Hash.new(0)
most_common = nil
most_common_count = 0
#text.chars.each do |char|
next unless is_letter?(char)
puts char + " ==> " + counter[char].to_s # To know the value on each iteration
counter[char] += 1
if counter[char] > most_common_count
most_common = char
most_common_count = counter[char]
puts [most_common_count, most_common] # To know when the if condition is executed
end
end
return [most_common_count, most_common]
end
private
def is_letter?(letter)
return letter =~ /[a-z]/i
end
end
counter = LetterCounter.new("Digital Punk")
p counter.calculate_most_common

Removing an Item from a LinkedList

I am trying to make a LinkedList assignment on ruby and was facing difficulties to do the remove method, so I searched in google and got the code from the remove method.
What I can't understand is the logic behind it, I can't understand how it works, how it works the logic to delete it.
class Node
attr_accessor :value, :next_node
def initialize(value, next_node = nil)
#value = value
#next_node = next_node
end
end
class LinkedList
def add(number)
new_node = Node.new(number)
if #head.nil?
#head = new_node
#tail = new_node
else
#tail.next_node = new_node
#tail = new_node
end
end
def get(index)
#your code here
node = #head
while index > 0 && node
node = node.next_node
index -= 1
end
node.value
end
def add_at (index, number)
if #head.nil?
#head = Node.new(number)
#tail = Node.new(number)
else
first = #head
index -= 1
while index > 0 && first
first = first.next_node
index -= 1
end
old_next = first.next_node
first.next_node = Node.new(number)
first.next_node.next_node = old_next
end
end
def remove (index)
node = #head
index -= 1
while index > 0 && node
node = node.next_node
index -= 1
end
node.next_node = node.next_node.next_node
end
end

Leetcode #501 - Find mode in binary tree: Trouble with recursion and pass-by-reference

I believe my code works in one scenario and breaks in another for the Leetcode problem #501 due to gaps in my understanding of recursion and pass-by-reference concepts in Ruby.
Using instance variables, the following code works:
def find_mode(root)
return [] if root.nil?
#modes = []
#counter = 1
#max = 0
#prev = nil
inorder(root)
#modes
end
def inorder(node)
return if node.nil?
inorder(node.left)
if !#prev.nil?
if #prev.val == node.val
#counter += 1
else
#counter = 1
end
end
if #counter > #max
#max = #counter
#modes = [node.val]
elsif #counter == #max
#modes << node.val
end
#prev = node
inorder(node.right)
end
However, the following alternate version does not work. Instead it times out.
def find_mode(root)
return [] if root.nil?
modes = []
counter = 1
max = 0
prev = nil
inorder(root, modes, prev, counter, max)
modes
end
def inorder(node, modes, prev, counter, max)
return if node.nil?
inorder(node.left, modes, node, counter, max)
if !prev.nil?
if prev.val == node.val
counter += 1
else
counter = 1
end
end
if counter > max
max = counter
modes = [node.val]
elsif counter == max
modes << node.val
end
prev = node
inorder(node.right, modes, node, counter, max)
end
What am I failing to understand in the second approach?

Ruby Program to solve Circular Primes below number x

I'm working on project Euler #35. I am getting the wrong number returned and I can't find where I have done wrong!
def is_prime?(num)
(2..Math.sqrt(num)).each { |i| return false if num % i == 0}
true
end
def is_circular?(num)
len = num.to_s.length
return true if len == 1
(len - 1).times do
new_n = cycle(num)
break unless is_prime?(new_n)
end
end
def cycle(num)
ary = num.to_s.split("")
return ary.rotate!.join.to_i
end
def how_many
circulars = []
(2..1000000).each do |num|
if is_prime?(num) && is_circular?(num)
circulars << num
end
end
p circulars.count
end
how_many #=> 14426
The returned number is '14426'. I am only returning the circular primes, supposedly the correct answer is '55'
I have edited your code with few fixes in Ruby way. Your mistake was including corect set of [a, b, c] three times to count, instead of counting them as a one circular prime number. Your answer was correct, while 55 is the number of unique sets.
require 'prime'
class Euler35
def is_circular?(num)
circulars_for(num).all?{ |el| ::Prime.instance.prime?(el) }
end
def circulars_for(a)
a.to_s.split("").length.times.map{|el| a.to_s.split("").rotate(el).join.to_i }
end
def how_many
circulars = []
::Prime.each(1_000_000) do |num|
continue if circulars.include?(num)
if is_circular?(num)
circulars << circulars_for(num)
end
end
circulars.count
end
end
puts Euler35.new.how_many # => 55

How to recreate .select()?

I'm trying to recreate the #select method. So far, I have array portion working, but when I try to call #my_select on a Hash, I get an empty Hash.
FYI, for starters, I had to recreate my own `#each' method. Here's that.
module Enumerable
def my_each
i = 0
while i < self.size
yield(self[i])
i += 1
end
self
end
Now, here's the #my_select method I created:
def my_select
if self.instance_of?(Array)
ret = []
self.my_each do |item|
ret << item if yield(item)
end
ret
elsif self.instance_of?(Hash)
ret = {}
self.my_each do |key, value|
if yield(key,value)
ret[key] = value
end
end
ret
end
end
end
...my input/output...
> h = { "a" => 100, "b" => 200, "c" => 300 }
> h.select { |k,v| k == "a"}
=> {"a"=>100}
> h.my_select { |k,v| k == "a"}
=> {}
Maybe you could change my_each to handle Hash as well?
def my_each
if self.instance_of?(Array)
i = 0
while i < self.size
yield(self[i])
i += 1
end
self
elsif self.instance_of?(Hash)
i = 0
arr = self.to_a
while i < arr.size
yield(arr[i][0], arr[i][1])
i += 1
end
self
end
end

Resources