From: "Guy N. Hurst" Date: 2001-05-11T16:58:31+09:00 Subject: [ruby-talk:14983] Re: Array search idiom "James B. Crigler" wrote: > > Here's a question about a ruby idiom. I have an array that contains > lines with mammal (classification. animal) pairs like the one found > in the code snippet. I need to find the first contiguous list of > primates. Assuming the array is called "a", here's how I solved the > problem. This does what I want, but is there a better way? > Hmm. What if you would like the second contiguous list of primates? Or perhaps the Nth list? What about for the others, like insectivora? class Array def foo(re) inject([[]]){|x,i| if i=~re then x[-1]< ["primates. tree shrews", "primates. lemurs", "primates. monkeys"] Idea ==== This looks to me like it could be a problem of finding the Nth contiguous list meeting any condition -- and allowing a parameter to set a threshhold for the list size, since a single item might not count as consecutive in some cases (e.g. primes). For a name, I think 'comb' is descriptive. Ruby Code ========= class Array def comb(min=2,&b) q=inject([[]]){|x,i| if b.call(i) then x[-1]<=min } end end a.comb{|i| i=~/^primates\./}[0] #=> ["primates. tree shrews", "primates. lemurs", "primates. monkeys"] a.comb{|i| i=~"^insectivora"}[0] #=> ["insectivora. shrews", "insectivora. moles", "insectivora. hedgehogs"] Explanation =========== I also have a few other versions, but this seems like the most powerful and concise. This particular one starts with an empty group, and fills it up with consecutive matches. As soon as there is no match, a second empty group is added to the container. Future matches are always added to the last group in the container. (Then all groups containing at least the minimum number of items are selected and returned.) I make use of the Array#inject method as shown on page 45 of the pickaxe book: class Array def inject(n) each{|v| n = yield(n,v)} n end end Other applications ================== For the math enthusiasts, this can be used to find 'consecutive' primes: odds=[3,5,7,9,11,13,15,17,19,21,23,25,27,29] odds.comb(2){|i| i.prime? } #=> [[3, 5, 7], [11, 13], [17, 19]] odds.comb(3){|i| i.prime? } #=> [[3, 5, 7]] Guy N. Hurst -- HurstLinks Web Development http://www.hurstlinks.com/ Norfolk, VA 23510 (757)623-9688 FAX 623-0433 PHP/MySQL - Ruby/Perl - HTML/Javascript