Simple iteration in a function problem

B

Blake Miller

i'm trying to do this, and I'm stuck


class holderOfYs

def initialize()
@ys = Array.new
end

def addX( x )
@ys << x
end

# this is the problem function. all I want is the specific (ONE)
element
# from the @ys array that matches the id, but when you iterate over the
# array, i can't find a way to only have one element returned
def getXById(id)
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
@ys.fetch(index)
end
end
end

class Y
@uniqueId

def getUniqueId
@uniqueId
end

end

class X < Y
def getUniqueId
super
end
end



I tried setting a variable like :
def getXById(id)
inst = X.new
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
inst = @ys.fetch(index)
end
end

inst
end

...but I'm not looking to instantiate a new X, and even that solution
seems to screw up the @ys array.
 
J

Joel VanderWerf

Blake Miller wrote:
...
# this is the problem function. all I want is the specific (ONE)
element
# from the @ys array that matches the id, but when you iterate over the
# array, i can't find a way to only have one element returned
def getXById(id)

Instead of:
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
@ys.fetch(index)
end
end

try this:

@ys.find {|x| x.getUniqueId == id}
 
M

Mike Fletcher

Blake said:
# this is the problem function. all I want is the specific (ONE)
element
# from the @ys array that matches the id, but when you iterate over the
# array, i can't find a way to only have one element returned
def getXById(id)
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
@ys.fetch(index)
end
end
end

Perhaps

def getXById( id )
@ys.detect { |y| y.getUniqueId == id }
end

See the docs for Enumerable#detect about handling what's returned if
nothing is found.
 
J

James Edward Gray II

i'm trying to do this, and I'm stuck

I've tried to answer your question and Rubyify your code a bit:

class YHolder
def initialize
@ys = Array.new
end

def add_y(y)
@ys << y
end
alias_method :<<, :add_y

def fetch_by_id(id)
@ys.find { |y| y.object_id == id }
end
alias_method :[], :fetch_by_id
end

class Y; end
class X < Y; end

holder, ids = YHolder.new, Array.new
10.times do
new_y_or_x = [Y, X][rand(2)].new

ids << new_y_or_x.object_id
holder << new_y_or_x
end

p holder # show the collection

# pick one by id
pick = ids[3]
p pick
p holder[pick]

# >> #<YHolder:0x1e2928 @ys=[#<Y:0x1e289c>, #<X:0x1e2874>, #<X:
0x1e284c>,
# >> #<Y:0x1e2824>, #<X:0x1e27fc>, #<Y:
0x1e27d4>,
# >> #<Y:0x1e27ac>, #<X:0x1e2784>, #<X:
0x1e275c>,
# >> #<Y:0x1e2734>]>
# >> 988178
# >> #<Y:0x1e2824>

__END__

Hope that helps.

James Edward Gray II
 
B

Blake Miller

Mike said:
Blake said:
# this is the problem function. all I want is the specific (ONE)
element
# from the @ys array that matches the id, but when you iterate over the
# array, i can't find a way to only have one element returned
def getXById(id)
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
@ys.fetch(index)
end
end
end

Perhaps

def getXById( id )
@ys.detect { |y| y.getUniqueId == id }
end

See the docs for Enumerable#detect about handling what's returned if
nothing is found.

I don't know where "detect" comes from (@ys is an array, and it doesn't
seem to be a method of Array)? however, I tried that and the result is
null, but I know for certain that the id being searched for does match
an element in the @ys array (because I wrote a function to print out the
ids in @ys)
 
B

Blake Miller

I don't know where "detect" comes from (@ys is an array, and it doesn't
seem to be a method of Array)? however, I tried that and the result is
null, but I know for certain that the id being searched for does match
an element in the @ys array (because I wrote a function to print out the
ids in @ys)

Sorry, missed that "Enumerable"
 
B

Blake Miller

# pick one by id
pick = ids[3]
p pick
p holder[pick]

# >> #<YHolder:0x1e2928 @ys=[#<Y:0x1e289c>, #<X:0x1e2874>, #<X:
0x1e284c>,
# >> #<Y:0x1e2824>, #<X:0x1e27fc>, #<Y:
0x1e27d4>,
# >> #<Y:0x1e27ac>, #<X:0x1e2784>, #<X:
0x1e275c>,
# >> #<Y:0x1e2734>]>
# >> 988178
# >> #<Y:0x1e2824>

__END__

Hope that helps.

James Edward Gray II

Note: The ids are strings. The @ys.find { |y| y.object_id == id } still
isn't working for me, i also tried y.object_id.equals(id) but I can't
seem to find the darn match : /
 
B

Blake Miller

I tried setting a variable like :
def getXById(id)
inst = X.new
@ys.each_with_index do |comp, index|
if( @ys[index].getUniqueId == id )
inst = @ys.fetch(index)
end
end

inst
end

...but I'm not looking to instantiate a new X, and even that solution
seems to screw up the @ys array.

I've also tried this:
def getXById(id)
matchingIndx = 0
@components.each_index do |index|
if( @components[index].getUniqueId == uniqueId )
matchingIndx = index
end
end

@components.fetch(matchingIndx)
end

but it just returns the 0th one every time (I'm assuming there wasn't a
match)
 
B

Blake Miller

Please show us your code, and make it as simple as possible. Like this:


class Widget

def initialize(title)
@components = Array.new
end

def add_component(component)
@components << component
end

def component(uniqueId) # note: uniqueId is a string
@components.find { |comp| comp.getUniqueId == uniqueId }
end
end

=========================================================
class SearchWidgetComponent
:attr_reader :uniqueId

def getUniqueId
@uniqueId
end
end

=============================
class SearchWidgetComparisonComponent

def getUniqueId
super
end
end


in my view index.rhtml, I have:
<% @sw.component("swComparisonComp1").some_func_call_on_swcc()... %>

I get an error " NoMethodError in Region#index" "You have a nil object
when you didn't expect it!" in index.rhtml at the
some_func_call_on_swcc() line
 
B

Blake Miller

I think perhaps the problem is how I'm comparing strings. What is the
proper way to compare two strings, like:


@str1 = "boo"

def meth(str)
if( @str1 == str )
end

meth("boo")

Is that the appropriate way to compare them?
 
B

Blake Miller

Paul said:
What? "uniqueId" is string? It cannot be a string, it has to be an ID,
something gotten with ".object_id", nothing else will do. And two
strings
with the same content do not necessarily have the same ID.

In your method "uniqueId", you should be returning "self.object_id".

In your code, I do not see where you acquire the ".object_id" of any
object.

Very basically, in order to solve a problem like this, you simply must
post
a short, terse, concise bit of code, that (1) can be run by a newsgroup
reader, and (2) shows the problem.

Posting bits and pieces of code, but never a short working example, is a
sure way to assure that this thread will go on forever.
Why can't it be a string, I can use whatever I want to identify an
object. Now, if you're saying it's not possible to compare two strings,
then I'd see your point. I can't make the code any simpler without
sacrificing understanding of what I'm trying to accomplish. It's very
simple, each component has an id, a unique id, that I assign to it,
which is a string, and is unique (I'll enforce that later). I have an
array of these components, and I want to search that array given a
string to find the matching component by id.
 
D

dblack

Hi --

class Widget

def initialize(title)
@components = Array.new
end

def add_component(component)
@components << component
end

def component(uniqueId) # note: uniqueId is a string
@components.find { |comp| comp.getUniqueId == uniqueId }
end
end

=========================================================
class SearchWidgetComponent
:attr_reader :uniqueId

No : on attr_reader; it's a method:

attr_reader :uniqueID
def getUniqueId
@uniqueId
end

You've now got two "get" methods for @uniqueID: the one attr_reader
created (which will be called uniqueID), and the one you've written.
end

=============================
class SearchWidgetComparisonComponent

def getUniqueId
super

super won't work here, unless this class is a subclass of
SearchWidgetComponent. And if it is a subclass, it will have that
method anyway. *And*... you don't need the method in the first place,
because of attr_reader :)

Also, you need a way to set as well as get your uniqueID values,
unless they're going to be something inherent in the object (the
object's object_id). Do you want attr_writer too?


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
B

Blake Miller

unknown said:
Hi --



No : on attr_reader; it's a method:

attr_reader :uniqueID


You've now got two "get" methods for @uniqueID: the one attr_reader
created (which will be called uniqueID), and the one you've written.


super won't work here, unless this class is a subclass of
SearchWidgetComponent. And if it is a subclass, it will have that
method anyway. *And*... you don't need the method in the first place,
because of attr_reader :)


Also, you need a way to set as well as get your uniqueID values,
unless they're going to be something inherent in the object (the
object's object_id). Do you want attr_writer too?


David
Noted, and changed. Sorry if I'm dragging this out, I know I left out a
couple details in the code I showed. Indeed
SearchWidgetComparisonComponent does, and has been extending
SearchWidgetComponent. My new code is like this:

class SearchWidget
def initialize
@components = Array.new
end

def add_component(component)
@components << component # these will always be subclass of
SearchWidgetComponent
end

def printcomps # i call this from index.rhtml, and it prints correctly
the 2 *different* component ids
str = ""
@components.each_with_index do |comp, index|
str += @components[index].uniqueId
end
str
end

def component(uniqueId)
@components.find { |comp| comp.uniqueId == uniqueId }
end
end

==================================
class SearchWidgetComponent
attr_accessor :uniqueId

def initialize(label, uniqueId) # see I pass a string as the id when I
init
@label = label
@uniqueId = uniqueId
end
end
==================================
class SearchWidgetComparisonComponent < SearchWidgetComponent
def initialize(label, uniqueId)
super(label, uniqueId)
@dbFields = Array.new
@showCalendar = false;
end
end

in my index.rhtml, I have (please note I've added comments below only to
this post, they are not in the source):
<%= @sw.printcomps %> # prints "swCompareComp1", and "anoth" (my two
unique ids)

# should return a SearchWidgetComparisonComponent
<% @obj = @sw.component("swCompareComp1") %>

# call method stylize() on the object
<%= @obj.stylize("sdbfPulldown", "scPulldown", "svfClass")%>


; however, the line that calls the stylize() method returns an error
saying " NoMethodError in Region#index......You have a nil object when
you didn't expect it! The error occured while evaluating nil.stylize"

Thanks ahead for the help yo. I've been tearin my hair out for 5 hours
now.
 
D

dblack

Hi --

unknown said:
Hi --



No : on attr_reader; it's a method:

attr_reader :uniqueID


You've now got two "get" methods for @uniqueID: the one attr_reader
created (which will be called uniqueID), and the one you've written.


super won't work here, unless this class is a subclass of
SearchWidgetComponent. And if it is a subclass, it will have that
method anyway. *And*... you don't need the method in the first place,
because of attr_reader :)


Also, you need a way to set as well as get your uniqueID values,
unless they're going to be something inherent in the object (the
object's object_id). Do you want attr_writer too?


David
Noted, and changed. Sorry if I'm dragging this out, I know I left out a
couple details in the code I showed. Indeed
SearchWidgetComparisonComponent does, and has been extending
SearchWidgetComponent. My new code is like this:

class SearchWidget
def initialize
@components = Array.new
end

def add_component(component)
@components << component # these will always be subclass of
SearchWidgetComponent
end

def printcomps # i call this from index.rhtml, and it prints correctly
the 2 *different* component ids
str = ""
@components.each_with_index do |comp, index|
str += @components[index].uniqueId
end
str
end

def component(uniqueId)
@components.find { |comp| comp.uniqueId == uniqueId }
end
end

==================================
class SearchWidgetComponent
attr_accessor :uniqueId

def initialize(label, uniqueId) # see I pass a string as the id when I
init
@label = label
@uniqueId = uniqueId
end
end
==================================
class SearchWidgetComparisonComponent < SearchWidgetComponent
def initialize(label, uniqueId)
super(label, uniqueId)
@dbFields = Array.new
@showCalendar = false;
end
end

in my index.rhtml, I have (please note I've added comments below only to
this post, they are not in the source):
<%= @sw.printcomps %> # prints "swCompareComp1", and "anoth" (my two
unique ids)

# should return a SearchWidgetComparisonComponent
<% @obj = @sw.component("swCompareComp1") %>

# call method stylize() on the object
<%= @obj.stylize("sdbfPulldown", "scPulldown", "svfClass")%>


; however, the line that calls the stylize() method returns an error
saying " NoMethodError in Region#index......You have a nil object when
you didn't expect it! The error occured while evaluating nil.stylize"

Thanks ahead for the help yo. I've been tearin my hair out for 5 hours
now.

I wish I could help. I can't spot anything that would cause @obj to
be nil, and when I try a standalone version of your code (essentially
what you've got minus the ERB markup), it runs fine.

Is it possible you've got symbols in one place (maybe when you create
the components) and strings in another?


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
B

Blake Miller

I wish I could help. I can't spot anything that would cause @obj to
be nil, and when I try a standalone version of your code (essentially
what you've got minus the ERB markup), it runs fine.

Is it possible you've got symbols in one place (maybe when you create
the components) and strings in another?


David
David, thanks for the help. I did create a test.rb file and the code
worked, as you said, as it should, so there must be something else in
the code that is changing the ids. I think it's time to start
commenting the heck out of everything till I find out where it is. I'll
keep looking and post the solution when I find it (hopefully soon!).
Thanks.
 
B

Blake Miller

unknown said:
Hi --



I wish I could help. I can't spot anything that would cause @obj to
be nil, and when I try a standalone version of your code (essentially
what you've got minus the ERB markup), it runs fine.

Is it possible you've got symbols in one place (maybe when you create
the components) and strings in another?


David
Ah you guys are gonna kill me now. I feel I must break out the
vaseline(sp??) and prepare to be hung.

Well, it just so happens I was passing the wrong uniqueId to the
component() function in the .rhtml file. 6 hours
later...unbelievable...I'm sure I'll be in this weekend making up the
time. The whole time I was reading "swCompareComp1" as
"swComparisonComp1". Unbelievable. Well, thanks a bunch guys, and
sorry for filling up your inboxes. Have good mosh-pitting!
 
J

James Edward Gray II

Well, it just so happens I was passing the wrong uniqueId to the
component() function in the .rhtml file. 6 hours
later...unbelievable...

Now the key is to learn a lesson from this, right? Here's my best
offer:

I can't remember the last time I had a six hour debugging session
after I started unit testing. Maybe it's time to add a new tool to
your belt...

James Edward Gray II
 
J

Joel VanderWerf

Paul said:
Blake Miller wrote: ... ...
2. It should not be a string because your goal is to compare two object IDs,
not strings. You are calling the variable "uniqueId", don't you think it
should be what it says it is? BTW use the Rubyish "unique_id" rather than
"uniqueId".

If the ID is coming from outside the program (a file say) or if the ID
needs to persist, then using a string makes sense. Ruby object ids don't
persist.
 
D

dblack

Hi --

1. I can see why this thread goes on so long -- instead of meeting my
request, you just changed the subject.

Paul, could you please stop being so confrontational? Your standards
are no higher than those of a lot of very accomplished programmers,
authors, and teachers on this list who do not find it necessary or
productive (neither of which it is) to adopt the kind of unpleasantly
didactic -- or, at many times, simply unpleasant -- tone that you
favor.

It seems to me that you might well have interesting things to say
about Ruby and programming in general, but right now they're smothered
in a mass of hostile, judgmental rhetoric. My advice would be just to
jettison it. If you want someone to clarify something, just ask them
what they meant. Don't add a lecture about their behavior.
Similarly, if you think someone has done something inadvisable, just
say so. Don't start with, "What? You did THAT?!" (or equivalent).

Thanks --


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
J

James Edward Gray II

Hi --



Paul, could you please stop being so confrontational? Your standards
are no higher than those of a lot of very accomplished programmers,
authors, and teachers on this list who do not find it necessary or
productive (neither of which it is) to adopt the kind of unpleasantly
didactic -- or, at many times, simply unpleasant -- tone that you
favor.

It seems to me that you might well have interesting things to say
about Ruby and programming in general, but right now they're smothered
in a mass of hostile, judgmental rhetoric. My advice would be just to
jettison it. If you want someone to clarify something, just ask them
what they meant. Don't add a lecture about their behavior.
Similarly, if you think someone has done something inadvisable, just
say so. Don't start with, "What? You did THAT?!" (or equivalent).

Yes, please.

James Edward Gray II
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,733
Messages
2,569,440
Members
44,830
Latest member
ZADIva7383

Latest Threads

Top