Skip to content

Instantly share code, notes, and snippets.

@Groxx
Created April 29, 2010 04:53
Show Gist options
  • Save Groxx/383161 to your computer and use it in GitHub Desktop.
Save Groxx/383161 to your computer and use it in GitHub Desktop.
Grab a portion of an array where the item number / index number has the same left-most digits as are passed.
class Array
# Returns a portion of an array in which the left-most numbers
# match the prefix. If 0 (or less) is passed, matches all
# single-digit numbers (same as [0..8]).
#
# === Warning
# This deals with the n-th items, <i><b>NOT</b></i> the n-th
# <i>indexes</i> (ie, it's 1 based, not 0 based), because it
# serves my needs currently, and allows zero to match all
# single-digit items. To get the indexes of the returned
# items, just subtract one.
#
# === Example
# * 0 => [1, 2, 3, 4, 5, 6, 7, 8, 9]
# * 1 => [1, 10, 11, 12, 13, ..., 100, ..., 157, ..., 199, etc.]
# * 12 => [12, 120, 121, 122, 123, ..., 1200, ..., 1257, ..., 1299, etc.]
#
# Non-optimal, but highly effective, and more readable. And
# though it's not optimal, it is very fast due to Ruby's
# efficient <tt><<</tt> array appending operation. This will
# also preserve any multi-dimensional array structure, where
# a more optimal solution may not.
#
# Optimal method unknown, will need benchmarking to determine,
# and that's not really necessary for the scale I'm working at.
def prefix(prefix)
return self[0..8] if prefix < 1
result = []
scale = 0
while true do
unless self[((left=prefix*10*scale-1)==-1 ? (scale==0 ? prefix-1 : prefix) : left)..((right=prefix*10*scale+(10*scale-1))==-1 ? prefix-1 : (scale > 0 ? right-1 : right))].nil?
self[((left=prefix*10*scale-1)==-1 ? (scale==0 ? prefix-1 : prefix) : left)..((right=prefix*10*scale+(10*scale-1))==-1 ? prefix-1 : (scale > 0 ? right-1 : right))].each do |item|
result << item
end
else
break
end
scale = scale * 10
scale = 1 if scale == 0
end
return result
end
# Returns a portion of an array in which the left-most index
# digits match the prefix. If a negative number is passed,
# matches all single-digit indexes (same as [0..9]).
#
# === Warning
# This deals with the n-th indexes, <i><b>NOT</b></i> the n-th
# <i>items</i>.
#
# === Example
# * -1 => [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# * 0 => [0]
# * 1 => [1, 10, 11, 12, 13, ..., 100, ..., 157, ..., 199, etc.]
# * 12 => [12, 120, 121, 122, 123, ..., 1200, ..., 1257, ..., 1299, etc.]
#
# Non-optimal, but highly effective, and more readable. And
# though it's not optimal, it is very fast due to Ruby's
# efficient <tt><<</tt> array appending operation. This will
# also preserve any multi-dimensional array structure, where
# a more optimal solution may not.
#
# Optimal method unknown, will need benchmarking to determine,
# and that's not really necessary for the scale I'm working at.
def prefix_index(prefix)
return self[0] if prefix == 0
return self[0..9] if prefix < 0
result = []
scale = 0
while true do
unless self[((left=prefix*10*scale-1)==-1 ? prefix : left+1)..((right=prefix*10*scale+(10*scale-1))==-1 ? prefix : right)].nil?
self[((left=prefix*10*scale-1)==-1 ? prefix : left+1)..((right=prefix*10*scale+(10*scale-1))==-1 ? prefix : right)].each do |item|
result << item
end
else
break
end
scale = scale * 10
scale = 1 if scale == 0
end
return result
end
end
@Groxx
Copy link
Author

Groxx commented Apr 29, 2010

I'm particularly proud of those massive slice definitions. Given that these define ranges, instead of iterating through every index, finding the ones that match by simple division operations, this should be extremely fast.

The slowest part is obviously that this returns a copy of the array via << on each item. Know a faster way that won't damage multi-dimensional / nested arrays? I'd love to use it.

@epochwolf
Copy link

Got ternaries?:

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment