Grouping elements of an array

Tanaka A. wrote:

I think this kind of problems which slices consecutive elements in an array
is not well supported in Ruby.

+1. There seems to be some real applications where that kind of tools
are nifty.

On Sun, Mar 21, 2010 at 7:58 AM, Tanaka A. [email protected] wrote:

enum.slice_between {|elt1, elt2| condition }.each {|ary| … }

Another possible idea is using Proc argument.
enum.foo(lambda {|elt| condition }) {|ary| … }

Tanaka A.

I must admit that when I made my post I was having difficulty
following your code for
Enumerable#slice_between
and the result you show for it of
[[“A”], [“B”], [“C”, “D”, “E”], [“F”, “G”]]
isn’t (I think) what the original poster wanted.
But I’ve just changed your condition of
(t2-t1) < 30
to
! ( (t2-t1) < 30 )
and that gives the wanted result of:
[[“A”, “B”, “C”], [“D”], [“E”, “F”], [“G”]]
and it was that that made my realise the meaning of “slice_between”.

One issue here is is it going to be usually better to “group by
similarity” or “slice at difference”,
which might affect what one calls such a method, and what condition is
tested?
For what I was doing it made sense to me to think in terms of grouping.
As posted, Steve W.'s problem was in terms of grouping, but could
be thought of as slicing at “difference”?

I hadn’t thought of using a Proc argument for the comparison.
I’ve just amended my Enumerable#each_group to do that,
and that looks (to my tired eyes at the moment!) cleaner than what I had
before.
So thanks for that Proc idea. (And it runs in 1.8 as well as in 1.9,
which isn’t the case if you use Enumerable::Enumerator?)

def group_for_sw2( arr )
lambda_compare = lambda { |aa, bb|
if bb[1] - aa[1] < 30 then 0 else -1 end
}
arrg = []
arr.each_group( lambda_compare ) do | aa |
aa.map! { |cc| cc[0] } # to preserve A, B, C objects, omit this
arrg << aa
end
arrg
end

Colin B.

2010/3/21 Colin B. [email protected]:

and that gives the wanted result of:
[[“A”, “B”, “C”], [“D”], [“E”, “F”], [“G”]]
and it was that that made my realise the meaning of “slice_between”.

Oops. You are right.

At 2010-03-20 08:57PM, “Tanaka A.” wrote:

G 300

would result in

[[A, B, C], [D], [E, F], [G]]

I think this kind of problems which slices consecutive elements in an array
is not well supported in Ruby.

Enumerable#each_slice is not usable because it slices for each fixed number
of elements.

I guess that’s why Enumerable#each_cons exists, to iterate over a
collection and look at the next n consecutive elements.

a = [[:A,0],[:B,15],[:C,35],[:D,100],[:E,205],[:F,215],[:G,300]]

all = []
current = [a[0][0]]

a.each_cons(2) do |m, n|
  if n[1] - m[1] < 30
    current << n[0]
  else
    all << current
    current = [n[0]]
  end
end

all << current
p all