0

I have an multidimensional Array in Ruby, like this:

[["2013-08-22 13:23:12 +0212", 100, 1], ["2013-09-22 14:25:12 +0123" , 123, 1]]

I would like to split the string in the first array position and the time to hours, minutes and seconds (and convert these to integers), so it will become:

[["2013-08-22", 13, 23, 12, "+0212", 100, 1], [.....]]

Does anyone know how to solve this problem?

4
  • 1
    My question is, how did you manage to arrive at your starting point? Maybe having a string representation of a datetime in a multidimensional array could be avoided and much more elegantly implemented. Commented Jul 20, 2017 at 13:09
  • These are data generated by a fax machine and are saved in a json format. In total I have an array with 52000 of the above arrays in it...and I have to convert them into the requested format, so I can process them. Commented Jul 20, 2017 at 15:51
  • So you have JSON -> multidimensional array -> array you want -> processed array. Assuming you're getting the JSON from an API, I'd think you can create a Fax client that skips some of the middle steps. Commented Jul 20, 2017 at 20:27
  • Please mark the answer that you found the most helpful as correct. Commented Jul 24, 2017 at 12:35

4 Answers 4

2

If you would like more readability, I suggest this:

require 'date'
array = [["2013-08-22 13:23:12 +0212", 100, 1], ["2013-09-22 14:25:12 +0123" , 123, 1]]
array.map do |date_time, a, b|
  date_time = DateTime.parse(date_time)

  [
    date_time.strftime('%F'), date_time.hour, date_time.min,
    date_time.sec, date_time.strftime('%z'), a, b
  ]
end

It makes it very clear what each element of the resulting array is. You should replace a and b with meaningful names if you have them.

Sign up to request clarification or add additional context in comments.

4 Comments

This looks very nice, although you are losing the "+0212" string. BTW, you need to change every d with date_time. :)
Upvoting this one. Ruby has an canonical way to parse a datetime, so we should use it, not reinvent it.
Thanks! Do you guys know of a nicer way to do date_time.to_date.to_s as well as date_Time.zone.to_s.gsub(':', ''). Those were two pieces that I didn't really like. It might even be best to pull them out into separate variables before creating the return value.
Sure, you can use formats. date_time.strftime('%F') and date_time.strftime('%z'), respectively.
1
[["2013-08-22 13:23:12 +0212", 100, 1],
 ["2013-09-22 14:25:12 +0123" , 123, 1]].

   map do |arr|
     arr.shift.split(/[: ]/) + arr # first position only
     # ⇓ this will convert hours, minutes and seconds  to integers
     # arr.shift.split(/[: ]/).map { |e| e[/\A\d+\z/] ? e.to_i : e } + arr
     # ⇓ this would work for all strings
     # arr.flat_map { |e| e.is_a?(String) ? e.split(/[: ]/) : e }
   end
#⇒ [
#  [0] [
#    [0] "2013-08-22",
#    [1] "13",
#    [2] "23",
#    [3] "12",
#    [4] "+0212",
#    [5] 100,
#    [6] 1
#  ],
#  [1] [
#    [0] "2013-09-22",
#    [1] "14",
#    [2] "25",
#    [3] "12",
#    [4] "+0123",
#    [5] 123,
#    [6] 1
#  ]
# ]

3 Comments

Very clean solution. Is it possible to convert hours, minutes and seconds to integer (as requested by OP) in a simple and concise way? (unlike my not-so-pretty solution)
Just wanted to thank you all, and especially you, as this post helped me the most!
0

Here's another option (converting hours, minutes and seconds to integers):

arr = [["2013-08-22 13:23:12 +0212", 100, 1], ["2013-09-22 14:25:12 +0123" , 123, 1]]

arr.map do |item|
  date, time, zone = item[0].split.map { |e| e.split(":") }
  [date, time.map(&:to_i), zone, item[1..-1]].flatten
end
#=> [["2013-08-22", 13, 23, 12, "+0212", 100, 1], ["2013-09-22", 14, 25, 12, "+0123", 123, 1]]

Comments

0

Non-destructive way. ref @mudasobwa answer

arr = [["2013-08-22 13:23:12 +0212", 100, 1], ["2013-09-22 14:25:12 +0123" , 123, 1]]
arr.map {|e| e[0].split(/[ :]/) + e[1..-1] } 
#=> [["2013-08-22", "13", "23", "12", "+0212", 100, 1], ["2013-09-22", "14", "25", "12", "+0123", 123, 1]]

1 Comment

Also taken from mudasobwa answer: arr.map {|e| e[0].split(/[ :]/).map { |e| e[/\A\d+\z/] ? e.to_i : e } + e[1..-1] } to convert hours, minutes and seconds to integer (as requested by OP).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.