[lnkForumImage]
TotalShareware - Download Free Software

Confronta i prezzi di migliaia di prodotti.
Asp Forum
 Home | Login | Register | Search 


 

Forums >

comp.lang.ruby

Tuples/Records/Quicky Objects + Read Only Arrays?

chris

1/1/2006 1:35:00 AM

Hi,

Does Ruby have a tuple or quicky object mechanism? I'm new to Ruby and
have become stuck on how to solve the following.

I'm testing adding items to a container, where each item is a pair of
strings. One is a name and another an alias. As they're added a check
should be performed to see if they're in the container, etc.

I've been using OCaml for a while, and for this I'd just use a list of
tuples of strings. What's the ruby way of doing this? Iterating over
a container/array is a doddle, that's not the problem. The problem is
really can you have quick pairs without making classes and so on?

While I'm at it, is there a read only array like container? Don't want
anyone messing with the internal array, they should not know that what's
returned is actually the internal representation or fiddle with it.
Don't care what they do with the elements in the array, only the array
itself.

class X
def initialize
@elements = Array.new
end

...

def elements
@elements.clone
end
end

Returning a clone of an array is fine, just wondered if you could
"write-protect" stuff in general.


Thanks,
Chris
6 Answers

Florian Groß

1/1/2006 2:15:00 AM

0

Wilson Bilkovich

1/1/2006 4:19:00 AM

0

On 12/31/05, Christopher Campbell <spamoff.danx@ntlworld.com> wrote:
> Hi,
>
> Does Ruby have a tuple or quicky object mechanism? I'm new to Ruby and
> have become stuck on how to solve the following.
>
> I'm testing adding items to a container, where each item is a pair of
> strings. One is a name and another an alias. As they're added a check
> should be performed to see if they're in the container, etc.
>
> I've been using OCaml for a while, and for this I'd just use a list of
> tuples of strings. What's the ruby way of doing this? Iterating over
> a container/array is a doddle, that's not the problem. The problem is
> really can you have quick pairs without making classes and so on?
>
> While I'm at it, is there a read only array like container? Don't want
> anyone messing with the internal array, they should not know that what's
> returned is actually the internal representation or fiddle with it.
> Don't care what they do with the elements in the array, only the array
> itself.
>
> class X
> def initialize
> @elements = Array.new
> end
>
> ...
>
> def elements
> @elements.clone
> end
> end
>
> Returning a clone of an array is fine, just wondered if you could
> "write-protect" stuff in general.
>
>

The Ruby equivalent of a tuple is pretty much an Array, since the
syntax is so lightweight.
a = [1, 2]
a.first == 1
a.last == 2

Possibly due to champagne, I can't think of a built-in object that
behaves the way you want.. but luckily, a quick implementation of it
shouldn't be hard:
class FunBox
def initialize
@names = {}
@aliases = {}
end

def <<(pair)
@names[pair.first] = pair.last
@aliases[pair.last] = pair.first
end

def alias_for_name(n)
@names[n]
end

def name_for_alias(a)
@aliases[a]
end
end


irb(main):060:0> f = FunBox.new
=> #<FunBox:0x2e15f00 @aliases={}, @names={}>
irb(main):061:0> f<<['joe', 'jim']
=> "joe"
irb(main):062:0> f.alias_for_name('joe')
=> "jim"
irb(main):063:0> f.name_for_alias('jim')
=> "joe"
irb(main):064:0>

Of course, given that you know OCaml, I'm probably telling you exactly
nothing you don't know.
I'm not aware of a way to freeze instance variables, such that you
couldn't still change them with Object#instance_variable_set


Robert Klemme

1/1/2006 5:08:00 PM

0

Christopher Campbell <spamoff.danx@ntlworld.com> wrote:
> Hi,
>
> Does Ruby have a tuple or quicky object mechanism? I'm new to Ruby
> and have become stuck on how to solve the following.

Easiest is to use arrays. But you can as well use a Struct:

>> Tuple=Struct.new :name, :alias
=> Tuple
>> t1=Tuple.new("name", "alias").freeze
=> #<struct Tuple name="name", alias="alias">
>> t2=Tuple.new("name", "alias").freeze
=> #<struct Tuple name="name", alias="alias">
>> t1.name = "changed?"
TypeError: can't modify frozen Struct
from (irb):14:in `name='
from (irb):14
from ?:0
>> t1 == t2
=> true

> I'm testing adding items to a container, where each item is a pair of
> strings. One is a name and another an alias. As they're added a
> check should be performed to see if they're in the container, etc.

I guess you rather want a Set so no multiple insertions can occur.
Alternatively you can use a Hash with your tuple as key if there is a
meaningful value.

> I've been using OCaml for a while, and for this I'd just use a list of
> tuples of strings. What's the ruby way of doing this? Iterating
> over a container/array is a doddle, that's not the problem. The
> problem is really can you have quick pairs without making classes and
> so on?
> While I'm at it, is there a read only array like container? Don't
> want anyone messing with the internal array, they should not know
> that what's returned is actually the internal representation or
> fiddle with it. Don't care what they do with the elements in the
> array, only the array itself.
>
> class X
> def initialize
> @elements = Array.new
> end
>
> ...
>
> def elements
> @elements.clone
> end
> end
>
> Returning a clone of an array is fine, just wondered if you could
> "write-protect" stuff in general.

Use #freeze as Florian pointed out.

>> require 'set'
=> true
>> container = Set.new
=> #<Set: {}>
>> container << ["name", "alias"].freeze
=> #<Set: {["name", "alias"]}>
>> container << ["name", "alias"].freeze
=> #<Set: {["name", "alias"]}>
>> container << ["no name", "alias"].freeze
=> #<Set: {["name", "alias"], ["no name", "alias"]}>
>> container.each {|nm,al| print "name=", nm, " alias=", al,"\n"}
name=name alias=alias
name=no name alias=alias
=> #<Set: {["name", "alias"], ["no name", "alias"]}>
>> container.each {|a| a << "does not work"}
TypeError: can't modify frozen array
from (irb):7:in `<<'
from (irb):7
from /usr/lib/ruby/1.8/set.rb:189:in `each'
from /usr/lib/ruby/1.8/set.rb:189:in `each'
from (irb):7
from :0

HTH

Kind regards

robert

chris

1/1/2006 5:57:00 PM

0

Thanks guys.

I see now we can use arrays and hashes to get

[{'name' => 'hi', 'c_alias' => 'c_hi'}]

or

[{:name => 'hi', :c_alias => 'c_hi'}]

which works dandy. I think my brain evaporated with the festivities
last night, heh.

Robert Klemme

1/1/2006 6:13:00 PM

0

Christopher Campbell <spamoff.danx@ntlworld.com> wrote:
> Thanks guys.
>
> I see now we can use arrays and hashes to get
>
> [{'name' => 'hi', 'c_alias' => 'c_hi'}]
>
> or
>
> [{:name => 'hi', :c_alias => 'c_hi'}]
>
> which works dandy. I think my brain evaporated with the festivities
> last night, heh.

Are you sure you recovered? I mean, what's the point in stuffing a hash
into a one element array?

robert

chris

1/1/2006 6:52:00 PM

0

Robert Klemme wrote:
> Christopher Campbell <spamoff.danx@ntlworld.com> wrote:
>> Thanks guys.
>>
>> I see now we can use arrays and hashes to get
>>
>> [{'name' => 'hi', 'c_alias' => 'c_hi'}]
>>
>> or
>>
>> [{:name => 'hi', :c_alias => 'c_hi'}]
>>
>> which works dandy. I think my brain evaporated with the festivities
>> last night, heh.
>
> Are you sure you recovered? I mean, what's the point in stuffing a hash
> into a one element array?

Heh... it was just an example, I will be stuffing lots of hashes into an
array.

def test_add_many_aliased
sample = [{:name => "abc", :c_alias => "c_abc"},
{:name => "hoop", :c_alias => "c_hoop"},
{:name => "blah", :c_alias => "c_blah"}]
elist = EnumList.new("many_aliased")

sample.each_index {|e| elist.add_alias(sample[e][:name],
sample[e][:c_alias])
assert_equal(sample[e][:name], elist[e].name)
assert_equal(sample[e][:c_alias],
elist[e].c_alias)}
end