Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
I have the following code:
class A
end
class B
end
a1 = A.new
a2 = A.new
b1 = B.new
b2 = B.new
array = [a1, a2, b1, b2]
hash = {}
array.each do |obj|
if hash[obj.class] = nil
hash[obj.class] = []
else
hash[obj.class] << obj
end
end
I want hash to be equal to
{ A => [a1,a2], B => [b1,b2] }
but it's telling me I can't use the << operator.
Let's sum it up.
if hash[obj.class] = nil
↑ you are resetting your pair every time your condition runs because of the unique equal that set hash[obj.class] to nil instead of testing its nillity. Use == instead.
Then, you are doing
array.each do |obj|
if hash[obj.class] == nil
hash[obj.class] = [] # if nil, initialize to new array
else # but because of the else, you are not...
hash[obj.class] << obj # doing this so you don't register the first object of each class.
end
end
Conclusion
array.each do |obj|
hash[obj.class] ||= [] # set hash[obj.class] to [] if nil (or false)
hash[obj.class] << obj
end
I think Enumerable#group_by is what you're looking for:
# ...
array = [a1, a2, b1, b2]
hash = array.group_by(&:class)
# => {A=>[#<A:0x0000000190dbb0>, #<A:0x000000018fa470>],
# B=>[#<B:0x000000018e5fe8>, #<B:0x000000018daa80>]}
(And as noted in the comments, the error you're getting is because you're setting hash[obj.class] to nil when you meant to test for equality with ==.)
Related
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 11 months ago.
Improve this question
When there are only two states for instance variable "a", either it has a value or not, and there is only one possible state for instance variable "b", it has a value. I can set "a" equal to "b" if "a" does not have a value via:
#a = nil
#b = "world"
def set_a
#a ||= #b
end
set_a
p #a
=> "world"
#a = "hello"
#b = "world"
def set_a
#a ||= #b
end
set_a
p #a
=> "hello"
But, what if there is more than one option for "a" to be set to? For example, I want to set instance variable "a" to either "b" or "c" depending on which has a value. In the program, only either "b" or "c" will have a value, always one but never both. Is there a way, using operators to write something like the following:
if #a == nil
if #b == nil
#a = #c
else
#a = #b
end
end
I was trying to write something that looks like this:
def set_a
#a ||= (#b || #c)
end
But, if #a had a value it would remain. Which is what I want. However, if #a was nil, then it would not take on the value of either #b or #c, it would remain nil.
Thank you for you time.
You can write
Module.const_defined?(:A) ? A : (B == true ? B : C)
to obtain the value of A.
A not defined
B = true
Module.const_defined?(:A) ? A : (B == true ? B : C)
#=> true
A not defined
B = false
Module.const_defined?(:A) ? A : (B == true ? B : C)
#=> 42
A = "cat"
B = false
C = 42
Module.const_defined?(:A) ? A : (B == true ? B : C)
#=> "cat"
See Module#const_defined?.
Constants and local variables will raise NameError if not defined. You probably want to use instance variables instead, as they are auto-vivified as nil when referenced even if they haven't been assigned to yet. For example:
#a ||= (#b || #c)
#=> nil
If either #a or #b are truthy, then things will probably work as you expect. However, if all three variables are falsey, then #a will be assigned the value of #c even if #c evaluates as nil or false.
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 6 years ago.
Improve this question
The to_chr function is supposed to return the encrypted array but converted to characters. I have tried many things and commented out the ones that didn't work.
class Encrypt
def initialize(code, string)
#code = code
#string = string
#encrypted = []
end
def to_byte
#string.each_byte do |c|
#encrypted.push(c + #code)
end
print #encrypted
end
def to_chr
n = #encrypted.length
# n.times do |i|
# #encrypted.push(i.chr)
# end
print #encrypted[0].chr
# #encrypted.each do |x|
# #encrypted.push(x.chr)
# end
# print #encrypted
end
end
goop = Encrypt.new(2, "hello")
goop.to_chr
#=> in `to_chr': undefined method `chr' for nil:NilClass (NoMethodError)
You create instance of Encrypted method, but you set #code = 2, #string = "Hello" and #encrypted = []. So if you call #encrypted[0], ruby return nil.
So you can modify your class like this:
class Encrypt
def initialize(code, string)
#code, #string, #encrypted = code, string, []
end
def to_byte
#string.each_byte { |c| #encrypted << c + #code }
end
def to_chr
to_byte if #encrypted.empty?
#encrypted.map(&:chr)
end
end
goop = Encrypt.new(2, "hello")
p goop.to_chr
# => ["j", "g", "n", "n", "q"]
I hope this helps
def to_chr
#encrypted.each do |i|
print i.chr
end
print "\n"
end
Make sure to call to_byte prior to to_chr
goop = Encrypt.new(2, "hello")
goop.to_byte
goop.to_chr
returns:
jgnnq
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
So I have a CSV that looks like this;
This is a test file
,,,,,,,,,,,
1122,Foo,Bar,FooBar
22321,Bar,Bar,Foo
11223,Foo,Foo,Foo,,,,,,,,,
12312/2423/1245,Foo,Foo,,,,,,,,
I want to parse it and have the following result in my array;
1122,Foo,Bar,FooBar
11223,Foo,Foo,Foo
22321,Bar,Bar,Foo
12312/2423/1245,Foo,Foo
My code;
class ReadCSVToArray
def initialize(file)
#array = CSV.read(file)
end
def compact_multi
y = []
#array.each { |i| i.compact! ; y << i unless i.blank? }
end
def item_rows
y = []
#array.each { |o|
if o[0].include? '/'; y << o ; end
if o[0].is_number? ; y << o ; end
}
end
end
the_list = ReadCSVToArray.new('/Users/davidteren/Desktop/read_test.csv')
the_list.compact_multi.item_rows.sort.each { |i| p i }
So as per above I'd like to chain several methods to get my results.
I have tried various things like;
class ReadCSVToArray
def initialize(file)
#array = CSV.read(file)
end
def compact_multi
y = []
#array.each { |i| i.compact! ; y << i unless i.blank? }
self
end
def item_rows
y = []
#array.each { |o|
if o[0].include? '/'; y << o ; end
if o[0].is_number? ; y << o ; end
}
self
end
end
No matter what I try I can't get it to work.
There's a problem with this line:
the_list.compact_multi.item_rows.sort.each { |i| p i }
This chain breaks down to 4 method calls:
the_list.compact_multi
the_list.item_rows
the_list.sort
the_list.each { |i| p i }
By returning self in your compact_multi and item_rows methods, you're ensuring that the next method in the chain is sent to your ReadCSVToArray instance. But there are no ReadCVSToArray#sort or ReadCSVToArray#each methods. You probably want to call them on instance variable #array.
result = CSV.parse 'This is a test file
,,,,,,,,,,,
1122,Foo,Bar,FooBar
22321,Bar,Bar,Foo
11223,Foo,Foo,Foo,,,,,,,,,
12312/2423/1245,Foo,Foo,,,,,,,,'
result.map(&:compact).reject { |l| l.size < 2 }
#⇒ [["1122", "Foo", "Bar", "FooBar"], ["22321", "Bar", "Bar", "Foo"],
# ["11223", "Foo", "Foo", "Foo"], ["12312/2423/1245", "Foo", "Foo"]]
Please note, that rejecting empties probably should be done more accurate. Hope it helps.
To get this:
the_list.compact_multi.item_rows.sort.each { |i| p i }
to work, compact_multi should return self and item_rows should return #array.
You seem to have two issues, the method chaining and getting the right result...
Your right result issue seems to be that you're assigning and building out this y array but you're not doing anything with it in any of those methods...
def compact_multi
y = []
#array.each { |i| i.compact! ; y << i unless i.blank? }
self
end
def item_rows
y = []
#array.each { |o|
if o[0].include? '/'; y << o ; end
if o[0].is_number? ; y << o ; end
}
self
end
what exactly is your goal? if its to maintain a result through the y array then make that an instance variable and initialize it in the initialize method...
As far as your chaining method issue if it's what I think you're trying to do which is unclear by your question then your methods should look like this...
class ReadCSVToArray
def initialize(file)
#result = []
#csv = CSV.read(file)
end
def compact_multi
#csv.each { |i| i.compact! ; #result << i unless i.blank? }
self
end
def item_rows
#csv.each { |o|
if o[0].include? '/'; #result << o ; end
if o[0].is_number? ; #result << o ; end
}
#result
end
end
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 9 years ago.
Improve this question
How can one generate a new list has all the elements of old-list except for some parts bracketted between line where f1(start_line) is true and f2(end_line) is true
Naive code
def remove_bracketted(orig_list)
ignore_flag = false
new_list = []
orig_list.each do |v|
if f1(v)
ignore_flag = true
elsif f2(v)
ignore_flag = false
else
new_list << v unless ignore_flag
end
end
end
For instance, with the following definitions of f1 and f2
def f1(v)
v == "{"
end
def f2(v)
v == "}"
end
when run on
foo(a,b)
{
s1
s2
s3
}
bar(a,b)
{
t1
t2
t3
}
Some other text
one should get
foo(a,b)
bar(a,b)
Some other text
Kindly note that f1 and f2 can be any function of type a -> Bool where list elements are all of type a and not just comparison to an open brace and close brace.
Edit:
I was looking for a solution like this which works if there is only one such pair
new_list = old_list.take_while(not(condition1)).concat(old_list.drop_while(not(condition2)))
This might be a place where the flip-flop operator would be useful:
def val1; '{' end
def val2; '}' end
p ['a','b','{','a','}','f','d','d'].reject{|x| true if (val1==x)..(val2==x)}
#=> ["a", "b", "f", "d", "d"]
p ['a','b','{','a','}','f','d','d'].select{|x| true if (val1==x)..(val2==x)}
#=> ["{", "a", "}"]
ScriptDevil, i guess some people won't like your way of making a question so i suggest asking it somewhat politer and not offer us a 'task' like we are in class. We are here to help and you should show us what you tried yourself.
Here is a way of doing what you want.
class String
def replace_between start, ending, replace_with
gsub(/#{start}[^#{ending}]*#{ending}/m, replace_with)
end
end
txt = %[
foo(a,b)
{
s1
s2
s3
}
bar(a,b)
{
t1
t2
t3
}
Some other text
]
puts txt.replace_between '{', '}', ''
# oo(a,b)
# bar(a,b)
# Some other text
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 8 years ago.
Improve this question
I need to write the method group_by by myself. This is what I have so far:
module Enumerable
def group_by(&b)
solution = {}
self.each {|key,val|
b.call(var)
solution = { key=> (val) }
}
end
end
ary = [1,2,3,4,5,6,7,8,9,10]
p ary.group_by() { |i| i%3 }
I don't get it. I hope you can help me.
module Enumerable
def group_by &b; inject({}){|h, e| (h[b.call(e)] ||= []).push(e); h} end
end
[1,2,3,4,5,6,7,8,9,10].group_by{|i| i % 3}
# => {1 => [1, 4, 7, 10], 2 => [2, 5, 8], 0 => [3, 6, 9]}
I'm not really sure how I can help apart from post a solution, but maybe some description with what you find difficult might help?
Few issues I notice:
You are using passing two arguments into the block when the array only has 1, the value
You call the block with var which doesn't exist in the current scope, maybe you meant val?
You dont check to see if anything already exists in the new solution dictionary
You overwrite the solution dictionary every time you loop over a new value in the array
Here is what I came up with:
module Enumerable
def group_by
solution = {}
each do |value|
key = yield value
if solution.key?(key)
solution[key] << value
else
solution[key] = [value]
end
end
solution
end
end
ary = [1, 2, 3, 4, 5]
p ary.group_by { |i| i % 3 }
output:
{1=>[1, 4], 2=>[2, 5], 0=>[3]}
you might want to check if a block has been given incase someone tries to use the function wrong, consider using the statement unless block_given? but maybe you can try implement this yourself.
Another solution for comparison:
module Enumerable
def group_by
{}.tap do |group|
each{ |value| (group[ yield(value) ] ||= []) << value }
end
end
end
uses tap to avoid the unsightly pattern of
thing = {}
# do stuff with thing
thing # return it
uses ||= to create the new collection array of not already present
Alternatively:
module Enumerable
def group_by
Hash.new{ |h,k| h[k]=[] }.tap do |group|
each{ |value| group[ yield(value) ] << value }
group.default = nil # remove the default_proc when done
end
end
end
From my backports gem:
module Enumerable
def group_by
return to_enum(:group_by) unless block_given?
result = {}
each do |o|
key = yield(o)
ary = result.fetch(key){ result[key] = [] }
ary << o
end
result
end
end
Contrary to all solutions presented so far, it passes RubySpec.