lib/linked/list.rb in linked-0.1.2 vs lib/linked/list.rb in linked-0.1.3
- old
+ new
@@ -77,22 +77,22 @@
# the list
def first(n = 1)
raise ArgumentError, 'n cannot be negative' if n < 0
- return first_item_after eol, count, n unless block_given?
+ return first_item_after eol, n, count unless block_given?
item = eol
items_left = count
items_left.times do
break if yield next_item = item.next
item = next_item
items_left -= 1
end
- first_item_after item, items_left, n
+ first_item_after item, n, items_left
end
# Access the last n item(s) in the list. The items will retain thier order.
# If a block is given each item, starting with the last in the list, will be
# yielded to it. The first item for which the block returns true and the
@@ -107,22 +107,22 @@
# the list
def last(n = 1)
raise ArgumentError, 'n cannot be negative' if n < 0
- return last_item_before eol, count, n unless block_given?
+ return last_item_before eol, n, count unless block_given?
item = eol
items_left = count
items_left.times do
break if yield prev_item = item.prev
item = prev_item
items_left -= 1
end
- last_item_before item, items_left, n
+ last_item_before item, n, items_left
end
# Overrides the Enumerable#count method when given no argument to provide a
# fast item count. Instead of iterating over each item, the internal item
# count is returned.
@@ -192,10 +192,22 @@
def shift
return nil if empty?
first.delete
end
+
+ # Check if an item is in the list.
+ #
+ # item - Item, or any object that may be in the list.
+ #
+ # Returns true if the given item is in the list, otherwise false.
+
+ def include?(item)
+ item.in? self
+ rescue NoMethodError
+ false
+ end
# Iterates over each item in the list, either in normal or reverse order. If
# a block is not given an enumerator is returned.
#
# reverse - flips the iteration order if true. Note that this option is
@@ -271,61 +283,70 @@
private def shrink(n = 1)
@item_count -= n
end
- # Private helper method that returns the first n items, starting just after
- # item, given that there are items_left items left. The following must hold
- # for the output to be valid:
+ # Protected helper method that returns the first n items, starting just
+ # after item, given that there are items_left items left. Knowing the exact
+ # number of items left is not cruicial but does impact speed. The number
+ # should not be lower than the actual ammount. The following must
+ # hold for the output to be valid:
# a) n > 0
# b) there are at least items_left items left
#
- # item - the Item just before the item to start from
- # items_left - the number of items left.
+ # item - the Item just before the item to start from.
# n - the number of items to return.
+ # items_left - the number of items left.
#
# Returns, for different values of n:
# n == 0) nil
# n == 1) an item if items_left > 0 or nil
# n > 1) an array of items if items_left > 0 or an empty array
- private def first_item_after(item, items_left, n)
+ protected def first_item_after(item, n, items_left = @item_count)
# Optimize for these cases
return nil if n == 0
+ return n > 1 ? [] : nil if item.next!.nil?
return item.next if n == 1
+
+ n = items_left if n > items_left
- (n > items_left ? items_left : n).times.map { item = item.next }
+ arr = Array.new n
+ n.times { |i| arr[i] = item = item.next }
+ arr
rescue StopIteration
- n > 1 ? [] : nil
+ arr.compact! || arr
end
- # Private helper method that returns the last n items, ending just before
- # item, given that there are items_left items left. The following must hold
- # for the output to be valid:
+ # Protected helper method that returns the last n items, ending just before
+ # item, given that there are items_left items left. Knowing the exact
+ # number of items left is not cruicial but does impact speed. The number
+ # should not be lower than the actual ammount. The following must hold for
+ # the output to be valid:
# a) n > 0
# b) there are at least items_left items left
#
# item - the Item just after the item to start from.
- # items_left - the number of items left.
# n - the number of items to return.
+ # items_left - the number of items left.
#
# Returns, for different values of n:
# n == 0) nil
# n == 1) an item if items_left > 0 or nil
# n > 1) an array of items if items_left > 0 or an empty array
- private def last_item_before(item, items_left, n)
+ protected def last_item_before(item, n, items_left = @item_count)
# Optimize for these cases
return nil if n == 0
+ return n > 1 ? [] : nil if item.prev!.nil?
return item.prev if n == 1
- # Truncate n if it is larger than the number of items
- # left
- n = (n > items_left ? items_left : n)
- (n - 1).downto(0).with_object(Array.new n) do |i, arr|
- arr[i] = item = item.prev
- end
+ n = items_left if n > items_left
+
+ arr = Array.new n
+ (n - 1).downto(0) { |i| arr[i] = item = item.prev }
+ arr
rescue StopIteration
- n > 1 ? [] : nil
+ arr.compact! || arr
end
end
end