Created
April 29, 2010 04:53
-
-
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.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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.