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