Ruby-ize me (or at least my code)

S

Seth Eliot

Hi all,

I am new to Ruby but find it interesting. To teach myself the language
I wrote a simple linked list implementation. It works just fine, but I
suspect that my "Java is showing" and that the same logic can be written
in a much more Ruby-ish fashion.

So I'd appreciate it if you can show me the Ruby way of implementing the
following functionality.

(The one thing I know is that I am not really taking advantage of OOP by
making my methods in LinkedListSe.rb just static utility methods… that's
fine for now)
(also "next_1" is just my way of not colliding with the reserved keyword
"next")

File: ElemLL.rb

class ElemLL

attr_accessor :data, :next_1

@data
@next_1
End

File: LinkedListSe.rb

require 'ElemLL'

# Adds element to end of linked list
def addData(data, head=nil)
insertData(data, head)
end

# Inserts Element at requested index in linked list.
# Shifts the element currently at that position (if any) and any
subsequent
# elements to the right (adds one to their indices)
def insertData(data, head, index=nil)

# special case if list currently empty (not initialized)
return newList(data) unless head

# Weakly typed languages have their downsides? :)
return unless head.class == ElemLL

# Initial values for first element
i = 1
prev = nil
curr = head
next_1 = curr.next_1

# Iterate through elements until we reach insertion point (or end of
list)
while (curr && (!index || i<index))
prev=curr
curr = next_1;
next_1 = curr.next_1 if curr;
i=i.next
end

# when new element is inserted, the current curr will actually be
next
next_1 = curr

# Create the new element at curr
curr = ElemLL.new
curr.data = data
curr.next_1=next_1

# Set the pointer *to* the new element
if (prev)
prev.next_1 = curr
else
head=curr
end

return head
end

def traverse(head)
puts "\nLinked List contents:"

curr = head
while(curr)
puts " #{curr.data}"
curr = curr.next_1
end
end

def newList(data)
head = ElemLL.new
head.data = data
return head
end
 
S

Seth E.

Just wanted to clarify: I know that there are better ways to do a
Linked List in Ruby... namely the Array object seems to have everything
you would need. So the code here is just an exercise, and I'm curious
how the same code can be made more ruby-ish

Also.....
# Weakly typed languages have their downsides? :)
return unless head.class == ElemLL

doh! I meant *dynamically* typed... I know Ruby is Strongly typed. And
I also *do* understand the advantages of a dynamically typed language
:)
 
D

David Vallner

--------------enigD87474276364386358C88070
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Seth said:
Hi all,
=20
I am new to Ruby but find it interesting. To teach myself the language= =20
I wrote a simple linked list implementation. It works just fine, but I= =20
suspect that my "Java is showing" and that the same logic can be writte= n=20
in a much more Ruby-ish fashion.
=20
So I'd appreciate it if you can show me the Ruby way of implementing th= e=20
following functionality.
=20
(The one thing I know is that I am not really taking advantage of OOP b= y=20
making my methods in LinkedListSe.rb just static utility methods=E2=80=A6= that's=20
fine for now)
(also "next_1" is just my way of not colliding with the reserved keywor= d=20
"next")
=20
File: ElemLL.rb
=20
class ElemLL
=20
attr_accessor :data, :next_1
=20

The following two lines don't in fact do anything and can be safely delet=
ed.
@data
@next_1
End
=20

The following should be methods of ElemLL. (There's not *much* Java
showing, is there?)
File: LinkedListSe.rb
=20
require 'ElemLL'
=20
# Adds element to end of linked list
def addData(data, head=3Dnil)
insertData(data, head)
end
=20
# Inserts Element at requested index in linked list.
# Shifts the element currently at that position (if any) and any=20
subsequent
# elements to the right (adds one to their indices)
def insertData(data, head, index=3Dnil)
=20
# special case if list currently empty (not initialized)
return newList(data) unless head
=20

If you're doing type-checking, raise an exception. This is a potential
Mysterious Bug. ("Nothing seem to be broke, it just doesn't work!")
# Weakly typed languages have their downsides? :)
return unless head.class =3D=3D ElemLL
=20
# Initial values for first element
i =3D 1
prev =3D nil
curr =3D head
next_1 =3D curr.next_1
=20
# Iterate through elements until we reach insertion point (or end o= f=20
list)
while (curr && (!index || i<index))
prev=3Dcurr
curr =3D next_1;
next_1 =3D curr.next_1 if curr;
i=3Di.next
end
=20
# when new element is inserted, the current curr will actually be=20
next
next_1 =3D curr
=20
# Create the new element at curr
curr =3D ElemLL.new
curr.data =3D data
curr.next_1=3Dnext_1
=20
# Set the pointer *to* the new element
if (prev)
prev.next_1 =3D curr
else
head=3Dcurr
end
=20
return head
end
=20

The following should be an implementation of #each:
def traverse(head) Axe following line.
puts "\nLinked List contents:"
=20
curr =3D head
while(curr)
Replace with "yield curr.data". For greater pleasure, have ElemLL
"include Enumerable".
puts " #{curr.data}"
curr =3D curr.next_1
end
end
=20

The Ruby equivalent of a constructor is the "special" (i.e. not really)
method initialize.
def newList(data)
head =3D ElemLL.new
head.data =3D data
return head
end
=20

Also, I personally prefer(red) opaque linked lists (in the school
assignments where I actually implemented those.) - ones where you don't
rely on having to supply the head node of a list to functions
manipulating it, but a structure encapsulating the list. Same here, I'd
avoid leaking the internal structure of the list.

David Vallner



--------------enigD87474276364386358C88070
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFO/qIy6MhrS8astoRAv8PAJ9Lz9ezcDDE+l/NsnTDSRMnOuE2EgCffA7U
ZyaGQPdWuI/dtXjOL4+UM6M=
=luo3
-----END PGP SIGNATURE-----

--------------enigD87474276364386358C88070--
 
D

David Vallner

--------------enigFEBC6EC6E3D22400610E86D4
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable
Just wanted to clarify: I know that there are better ways to do a=20
Linked List in Ruby... namely the Array object seems to have everything= =20
you would need. =20

The Array object isn't a linked list, it's an array-backed list. (The
damage freshman courses cause by making students believe linked lists
are in any way amazing. In fact, in any scenario where there's a
reasonable upper bound on the number of items in the list, an
array-backed implementation will implement a linked-list implementation
in terms of both speed and memory efficiency.)

David Vallner


--------------enigFEBC6EC6E3D22400610E86D4
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFO/s+y6MhrS8astoRAgCbAJ43/WdozZlPCAQTskstEbJvcNldjACdE3Y+
B/nuWHXPkNPJYmhgH9IjSVw=
=m0tL
-----END PGP SIGNATURE-----

--------------enigFEBC6EC6E3D22400610E86D4--
 
E

Eero Saynatkari

--Wo0oCZYLrer5S3Oe
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline
Content-Transfer-Encoding: quoted-printable

Hi all,
=20
I am new to Ruby but find it interesting. To teach myself the language= =20
I wrote a simple linked list implementation. It works just fine, but I= =20
suspect that my "Java is showing" and that the same logic can be written= =20
in a much more Ruby-ish fashion.

It is mostly an imperative style that is showing for some odd reason :)
Instead of critiquing, I will give you an alternative implementation to
munch upon.
So I'd appreciate it if you can show me the Ruby way of implementing the= =20
following functionality.
=20
(The one thing I know is that I am not really taking advantage of OOP by= =20
making my methods in LinkedListSe.rb just static utility methods??? that'= s=20
fine for now)
(also "next_1" is just my way of not colliding with the reserved keyword= =20
"next")

# I have not actually run this code, just typing out at work
class Node
include Enumerable

attr_accessor 'data', 'succ'

# New node with the given data
def new(data, succ =3D nil)
@data, @succ =3D data.first, succ
end

# Chainable append from arbitrary data
def <<(data)=20
@succ =3D Node.new data
@succ
end

# Insert a node at a given position
def insert_at(pos, data)
return Node.new(data, self) if pos =3D=3D 0
=20
@succ.insert_at((pos - 1), data)
self
end

# Traversal
def each(&block)
yield @data
@succ.each &block
end

# Stringimafy
def to_s()
map {|data| data.to_s}.join ' -> '
end
end

list =3D Node.new('foo') << 'bar' << 'baz' << 'quux'


--Wo0oCZYLrer5S3Oe
Content-Type: application/pgp-signature
Content-Disposition: inline

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (FreeBSD)

iD8DBQFFPAVx7Nh7RM4TrhIRAvC5AKCuOovOhuA4O71rgZPUaUpkVpDc5ACgqjFu
UtNmH+gv6EMOFhUHSE4RFOk=
=GM9x
-----END PGP SIGNATURE-----

--Wo0oCZYLrer5S3Oe--
 
D

David Vallner

--------------enig0B835177C357245373B7F355
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

Eero said:
# Stringimafy

*facedesk*

Do I see a new rubyism being born?

David Vallner


--------------enig0B835177C357245373B7F355
Content-Type: application/pgp-signature; name="signature.asc"
Content-Description: OpenPGP digital signature
Content-Disposition: attachment; filename="signature.asc"

-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.5 (MingW32)

iD8DBQFFPAxby6MhrS8astoRApspAJ4kQrgtIHwKwyFZdx6uDoZsWG8GxQCfbgWX
EhVIKapYmLdGZ5qtVASlkF4=
=6ayP
-----END PGP SIGNATURE-----

--------------enig0B835177C357245373B7F355--
 
S

Seth E.

Thanks Eero. That is quite an eye-opener, and was exactly what I was
looking for.
# I have not actually run this code, just typing out at work

...which probably explains what I am about to ask you, but I thought I
would double check

Eero said:
# New node with the given data
def new(data, succ = nil)
@data, @succ = data.first, succ
end

This should actually be this, right?

# New node with the given data
def initialize(data, succ = nil)
@data, @succ = data, succ
end

Nonetheless, with a few tweaks your example worked fine, and was quite
educational. Thanks again!
 

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,764
Messages
2,569,564
Members
45,040
Latest member
papereejit

Latest Threads

Top