conlon
conlon

Reputation: 11

Ruby: Combining simple array elements

     array = [
     ["sean", "started", "shift", "at", "10:30:00"],
     ["anna", "started", "shift", "at", "11:00:00"],
     ["sean", "started", "shift", "at", "10:41:45"],
     ["anna", "finished", "shift", "at", "11:30:00"],
     ["sean", "finished", "shift", "at", "10:48:45"],
     ["sean", "started", "shift", "at", "11:31:00"],
     ["sean", "finished", "shift", "at", "11:40:00"]
     ]

Few things to consider

  1. if you look at sean's entries - there are 2 entries for 'start times' one at 10:30:00 and also at 10:41:45 . The system can record multiple 'start times' but only one 'Finished' time. The logic is to pair first 'started' & first 'finished' and combine them.

  2. How to skip the duplicated 'start time' entries (such as Sean's) and get a desired output as below...

    array = [
    ["sean", "started", "shift", "at", "10:30:00", "finished", "shift", "at", "10:48:45"],
    ["anna", "started", "shift", "at", "11:00:00", "finished", "shift", "at", "11:30:00"],
    ["sean", "started", "shift", "at", "11:31:00", "finished", "shift", "at", "11:40:00"]
    ]

Theres no easy way is it?

Upvotes: 0

Views: 75

Answers (2)

Uri Agassi
Uri Agassi

Reputation: 37419

array.group_by(&:first).map do |person, events| 
  events.chunk { |_, event_type| event_type }.each_slice(2).map do |(_, (start, _)), (_, (finish, _))|  
    %W(#{p} started shift at #{start[4]} finished shift at #{finish[4]}) 
  end
end

# => [
# => ["sean", "started", "shift", "at", "10:30:00", "finished", "shift", "at", "10:48:45"],
# => ["sean", "started", "shift", "at", "11:31:00", "finished", "shift", "at", "11:40:00"],
# => ["anna", "started", "shift", "at", "11:00:00", "finished", "shift", "at", "11:30:00"]
# => ]

Upvotes: 1

Amadan
Amadan

Reputation: 198496

started = {}
result = []
array.each do |name, *event|
  if event[0] == "started" && !started[name]
    result << (started[name] = [name] + event)
  elsif event[0] == "finished" && started[name]
    started[name].concat(event)
    started[name] = nil
  end
end
result

EDIT Completely agree with fotanus, BTW.

EDIT2 Forgot to change a variable name. Also: logic. You take each row in turn. started will contain any records that have started but not yet finished. So, take a row; if it's "started", and only if we don't know that that person already started, remember the start. If it's "finished", and only if we already know the person has started, finish up the record by appending the finish info.

Upvotes: 0

Related Questions