Ruby-ize me (or at least my code)

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

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…

Seth E. wrote:

# 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
:slight_smile:

Seth Eliot wrote:

(The one thing I know is that I am not really taking advantage of OOP by

The following two lines don’t in fact do anything and can be safely
deleted.

@data
@next_1
End

The following should be methods of ElemLL. (There’s not much Java
showing, is there?)

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

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!”)

list)

end

return head

end

The following should be an implementation of #each:

def traverse(head)
Axe following line.
puts “\nLinked List contents:”

curr = head
while(curr)

Replace with “yield curr.data”. For greater pleasure, have ElemLL
“include Enumerable”.

    puts "   #{curr.data}"
    curr = curr.next_1
end

end

The Ruby equivalent of a constructor is the “special” (i.e. not really)
method initialize.

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

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 V.

Seth E. wrote:

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.

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 V.

On 2006.10.23 07:51, Seth Eliot wrote:

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.

It is mostly an imperative style that is showing for some odd reason :slight_smile:
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
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”)

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 = nil)
@data, @succ = data.first, succ
end

Chainable append from arbitrary data

def <<(data)
@succ = Node.new data
@succ
end

Insert a node at a given position

def insert_at(pos, data)
return Node.new(data, self) if pos == 0

@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 = Node.new(‘foo’) << ‘bar’ << ‘baz’ << ‘quux’

Eero S. wrote:

Stringimafy

facedesk

Do I see a new rubyism being born?

David V.

David V. [email protected] writes:

in terms of both speed and memory efficiency.)
But you can’t do DLX with an array! :wink:

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 S. wrote:

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!