Velocity Reviews > Ruby > Grouping elements of an array

# Grouping elements of an array

Steve Wilhelm
Guest
Posts: n/a

 03-18-2010
I have an array of records that contain timestamps at random intervals.
The records are ordered by timestamp.

I would like to convert the array into an array of arrays; each subarray
would contain "grouped records." Grouping would occur if the timestamp
of the next element in the original array is within thirty seconds of
the current element.

Example (second column is timestamp in seconds starting from zero).

A 0
B 15
C 35
D 100
E 205
F 215
G 300

would result in

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

Any help on how to do this in the "Ruby Way" would be appreciated.

- Steve W.
--
Posted via http://www.ruby-forum.com/.

Josh Cheek
Guest
Posts: n/a

 03-19-2010
[Note: parts of this message were removed to make it a legal post.]

On Thu, Mar 18, 2010 at 4:50 PM, Steve Wilhelm <(E-Mail Removed)> wrote:

> I have an array of records that contain timestamps at random intervals.
> The records are ordered by timestamp.
>
> I would like to convert the array into an array of arrays; each subarray
> would contain "grouped records." Grouping would occur if the timestamp
> of the next element in the original array is within thirty seconds of
> the current element.
>
> Example (second column is timestamp in seconds starting from zero).
>
> A 0
> B 15
> C 35
> D 100
> E 205
> F 215
> G 300
>
> would result in
>
> [[A, B, C], [D], [E, F], [G]]
>
> Any help on how to do this in the "Ruby Way" would be appreciated.
>
> - Steve W.
> --
> Posted via http://www.ruby-forum.com/.
>
>

A 0
B 20
C 40

Does that become
[[A,B],[B,C]] or [[A,B,C]] or something else? The congruence class here is
unclear.

Steve Wilhelm
Guest
Posts: n/a

 03-19-2010
Josh Cheek wrote:
> On Thu, Mar 18, 2010 at 4:50 PM, Steve Wilhelm <(E-Mail Removed)>
> wrote:
>
>> A 0
>>
>> Any help on how to do this in the "Ruby Way" would be appreciated.
>>
>> - Steve W.
>> --
>> Posted via http://www.ruby-forum.com/.
>>
>>

> A 0
> B 20
> C 40
>
> Does that become
> [[A,B],[B,C]] or [[A,B,C]] or something else? The congruence class here
> is
> unclear.

It would be [[A,B,C]].

- Steve W.
--
Posted via http://www.ruby-forum.com/.

Roger Braun
Guest
Posts: n/a

 03-19-2010
Hi

On Thu, Mar 18, 2010 at 11:50 PM, Steve Wilhelm <(E-Mail Removed)> wrote:
> I have an array of records that contain timestamps at random intervals.
> The records are ordered by timestamp.
>
> I would like to convert the array into an array of arrays; each subarray
> would contain "grouped records." Grouping would occur if the timestamp
> of the next element in the original array is within thirty seconds of
> the current element.
>
> Example (second column is timestamp in seconds starting from zero).
>
> A 0
> B 15
> C 35
> D 100
> E 205
> F 215
> G 300
>
> would result in
>
> [[A, B, C], [D], [E, F], [G]]
>
> Any help on how to do this in the "Ruby Way" would be appreciated.

1 arr = [0,15,35,100,205,300]
2 arr2 = [0, 20, 40]
3
4 def group(array)
5 array.map!{|e| [e]}
6 array.inject([]) do |r, e|
7 if r == [] or e[0] - r.last.last > 30 then
8 r.push(e)
9 else
10 r[-1].push(e[0])
11 end
12 r
13 end
14 end
15
16 puts arr.inspect
17 puts group(arr).inspect
18 puts arr2.inspect
19 puts group(arr2).inspect

--
Roger Braun
http://yononaka.de
http://www.velocityreviews.com/forums/(E-Mail Removed)-tuebingen.de

Josh Cheek
Guest
Posts: n/a

 03-19-2010
[Note: parts of this message were removed to make it a legal post.]

On Thu, Mar 18, 2010 at 4:50 PM, Steve Wilhelm <(E-Mail Removed)> wrote:

> I have an array of records that contain timestamps at random intervals.
> The records are ordered by timestamp.
>
> I would like to convert the array into an array of arrays; each subarray
> would contain "grouped records." Grouping would occur if the timestamp
> of the next element in the original array is within thirty seconds of
> the current element.
>
> Example (second column is timestamp in seconds starting from zero).
>
> A 0
> B 15
> C 35
> D 100
> E 205
> F 215
> G 300
>
> would result in
>
> [[A, B, C], [D], [E, F], [G]]
>
> Any help on how to do this in the "Ruby Way" would be appreciated.
>
> - Steve W.
> --
> Posted via http://www.ruby-forum.com/.
>
>

Here is my solution, it's conceptually similar to Roger's, though differs in
implementation http://gist.github.com/337195

Josh Cheek
Guest
Posts: n/a

 03-19-2010
[Note: parts of this message were removed to make it a legal post.]

On Thu, Mar 18, 2010 at 9:29 PM, Urabe Shyouhei <(E-Mail Removed)>wrote:

> Roger Braun wrote:

>
> You should really know about Enumerable#group_by.
>
> irb(main):001:0> [0,15,35,100,205,300].group_by {|i| i/100 }
> => {0=>[0, 15, 35], 1=>[100], 2=>[205], 3=>[300]}
>
>
>

Your results are correct only because of a happenstance of the data. Add 99
in there, it should group with 100, but it groups with the 0...100
congruence class

ruby-1.9.1-p378 > [0,15,35,99,100,205,300].group_by {|i| i/100 }
=> {0=>[0, 15, 35, 99], 1=>[100], 2=>[205], 3=>[300]}

Because these groups are relative to each other, I think you must do
something like Roger or I did, where you iterate through the list and
compare it to the groups.

Roger Braun
Guest
Posts: n/a

 03-19-2010
On Fri, Mar 19, 2010 at 4:29 AM, Urabe Shyouhei <(E-Mail Removed)> wrote:
> Roger Braun wrote:

>
> You should really know about Enumerable#group_by.
>
> irb(main):001:0> [0,15,35,100,205,300].group_by {|i| i/100 }
> => {0=>[0, 15, 35], 1=>[100], 2=>[205], 3=>[300]}

This does not solve the problem.

irb(main):011:0> [0,15,35,99,100,205,300].group_by{|i| i/100}
=> {0=>[0, 15, 35, 99], 1=>[100], 2=>[205], 3=>[300]}

but should be

[[0, 15, 35], [99, 100], [205], [300]]

at least if I understood the problem correctly.

--
Roger Braun
http://yononaka.de
(E-Mail Removed)-tuebingen.de

Robert Klemme
Guest
Posts: n/a

 03-19-2010
On 03/18/2010 11:50 PM, Steve Wilhelm wrote:
> I have an array of records that contain timestamps at random intervals.
> The records are ordered by timestamp.
>
> I would like to convert the array into an array of arrays; each subarray
> would contain "grouped records." Grouping would occur if the timestamp
> of the next element in the original array is within thirty seconds of
> the current element.
>
> Example (second column is timestamp in seconds starting from zero).
>
> A 0
> B 15
> C 35
> D 100
> E 205
> F 215
> G 300
>
> would result in
>
> [[A, B, C], [D], [E, F], [G]]
>
> Any help on how to do this in the "Ruby Way" would be appreciated.

Assuming records are ordered already - otherwise you need a sort in between.

require 'pp'

dat = <<DDD.each_line.map {|l|r = l.split;r[1]=r[1].to_i;r}
A 0
B 15
C 35
D 100
E 205
F 215
G 300
DDD

pp dat

gr = dat.inject [] do |agg, rec|
if agg.last && rec[1] - agg.last.last[1] <= 15
agg.last << rec
agg
else
agg << [rec]
end
end

pp gr

Note: I don't claim that this is *the* Ruby way.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/

Steve Wilhelm
Guest
Posts: n/a

 03-19-2010
> I have an array of records that...

Thank you all for your solutions.

The time they saved me, I'll spend learning about the techniques you
employed.

- Steve W.

--
Posted via http://www.ruby-forum.com/.

¿½ ¤å¤¯
Guest
Posts: n/a

 03-19-2010
[Note: parts of this message were removed to make it a legal post.]

Hello, I am new to Ruby. Below is my solution:

a=[0, 15, 35, 100, 205, 215, 300]
b=[]
c=[]
d=a[0]
a.each do |i|
if i - d < 30
c << i
else
b << c
c=[i]
end
d =i
end
if c.size > 0
b << c
end

p b