Problems Keeping an Object in an Array, Ruby Issues and Rails Issues

Problems keeping an object in an array, Ruby issues and Rails issues

TL;DR: The controller's are stateless, they just see the incoming request. To have a list outlive the current request, you need to persist the list in either the session or in the database, depending on how long you want it to live and other considerations.

There are some other issues...

Don't used defined? for that, in fact, don't use defined? for anything. It doesn't have many legit application-level uses. In this case, libraryshelf is a local variable, and on its first reference in the method it will always not be defined.

Operate directly on @listofbooks and just check @listofbooks or @listofbooks.nil?.

Here are a few working (I think) versions...

def add_book name
@listofbooks = [] unless @listofbooks
@listofbooks << name
end

def add_book name
@listofbooks ||= []
@listofbooks << name
end

def add_book name
@listofbooks = @listofbooks.to_a.push name # yes, works even if @listofbooks.nil?
end

Aha, your revised post is better ... as noted in TL;DR: because Rails recreates controller objects on each request, you will need to persist anything you want next time around in your session or database.

The original post kind of fooled us by also clobbering @listofbooks every time through the method, so we thought it was really a ruby question.

Ruby Array Elements

The code doesn't know it needs to include a digit/letter from every group. The sample takes random signs and since you a basically sampling 0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz there is a possibility that all the signs will not be digits.

The easiest way to fix it is to check if a sign from every group is in the "password" and then replace a random sign with a sign from group that is not present.

If I were to program this I would do it like that

def random_from_range(range)
range.to_a.sample.to_s
end

def passGen(numbers, lowercase, uppercase)
result = ''
possibleSigns = []
if numbers == 1
range = (0..9)
result += random_from_range(range)
possibleSigns += range.to_a
end
if lowercase == 1
range = ('A'..'Z')
result += random_from_range(range)
possibleSigns += range.to_a
end
if uppercase == 1
range = ('a'..'z')
result += random_from_range(range)
possibleSigns += range.to_a
end
desired_lenth = 10
while result.length < desired_lenth
result += possibleSigns.sample.to_s
end
result
end

puts passGen(1,1,1)

Only push objects into array if the scope returns records, not a blank

Wow you just made it way easier with extra code how about this

class Member
has_many :snacks

def find_snacks(snacktypes)
snacks.red.snacktypefind(snacktypes)
end

end

This turns into

"SELECT snacks.* FROM snacks WHERE snacks.member_id = YOUR_MEMBER_ID AND snacks.color = 'red' AND snacks.snacktype IN (YOUR snacktypes array)"

Currently your implementation we will call it "query and push" has drawbacks.

First this will create multiple miniature collections probably composed of single objects. This will be hell to iterate as you will have to nest iteration to actually access the object.
Second this will create multiple queries 1 for each snacktype which will degrade performance.

What you really want is to chain query methods to narrow everything down to a single ActiveRecord::Relation that will contain just the elements you need. This will execute a single query and when you iterate the piped object will be the actual object you want to access and not another ActiveRecord::Relation which would have to be iterated again.

ActiveRecord Query Methods the great part about scopes and query chains are that they don't get executed until the chain is complete allowing you to easily add and remove conditions in a very granular manner. This way you can target the data in the database explicitly instead of loading it into memory and cleaning it up from there.

Backtracking and combinatronics problem in Ruby

require 'set'

def find_em(arr, n)
arr.combination(n)
.select do |a|
[1, n].include?(a.map { |s| s[0] }.uniq.size) &&
[1, n].include?(a.map(&:size).uniq.size)
end.uniq(&:to_set)
end
find_em ['Y', 'Y', 'Z', 'ZZ', 'X', 'XX', 'Y'], 3
#=> [["Y", "Y", "Y"], ["Y", "Z", "X"]]
find_em ['X', 'Y', 'YY', 'ZZ', 'ZZZ'], 3
#=> [["X", "YY", "ZZZ"]]
find_em ['X', 'Y', 'YY', 'ZZ', 'ZZ'], 3
#=> []

In the first example, without .uniq(&:to_set) we would obtain

find_em ['Y', 'Y', 'Z', 'ZZ', 'X', 'XX', 'Y'], 3
#=> [["Y", "Y", "Y"], ["Y", "Z", "X"], ["Y", "Z", "X"], ["Z", "X", "Y"]]

See Array#combination and Array#uniq.

Ruby reverse.each_with_index and delete_at causing problems in latest Ruby/Rails

You're deleting using the reversed index, but from the original array.

To get the "real" index, instead of one counting from the end of the array, you need to flip it around:

arr1.delete_at(-index - 1)

... but you should almost certainly be using reject! or delete_if instead:

require "set"

unwanted_colors = @arr2.map(&:color).to_set
@arr1.reject! { |el| unwanted_colors.include?(el.color) }

Can I make this Ruby code faster and/or use less memory?

You've got the right idea. However, Ruby has a built-in class that's perfect for building sets of unique items: Set.

animals = ["cat horse", "dog", "cat dog bird", "dog sheep", "chicken cow"]

unique_animals = Set.new

animals.each do |str|
unique_animals.merge(str.split)
end
# => cat
# horse
# dog
# bird
# sheep
# chicken
# cow

Or...

unique_animals = animals.reduce(Set.new) do |set, str|
set.merge(str.split)
end

Under the covers Set actually uses a Hash to store its items, but it acts more like an un-ordered Array and responds to all of the familiar Enumerable methods (each, map, select, etc.). If you need to turn it into a real Array, though, just use Set#to_a.



Related Topics



Leave a reply



Submit