Slice an array into tuples

Hi,

I’d like to slice an array of n elements into an array of {Int32, Int32, String, String} tuples. Just like this:

an_array = [42, 43, "foo", "bar", 44, 45, "baz", "fuu"]
an_array_of_tuples(an_array) # => [{42, 43, "foo", "bar"}, {44, 45, "baz", "fuu"}]

I found each_slice method with is pretty nice, that I can call to an_array. But it returns an array of arrays. Maybe I could use it and then try to convert each sub-array into a tuple, but I’m not sure if it would be the best way to go.

What could be the best practice for such an_array_of_tuples processing? Any help appreciated. Thanks.

Hi!

You can do something like this:

def an_array_of_tuples(array, tuple : Tuple.class)
  an_array_of_tuples_impl(array, tuple)
end

def an_array_of_tuples_impl(array, tuple : T.class) forall T
  result = [] of T

  i = 0
  while i < array.size
    result <<
      {% begin %}
        {
          {% for type, index in T %}
            array[i + {{index}}].as({{type}}),
          {% end %}
        }
      {% end %}
    i += {{ T.size }}
  end

  result
end

an_array = [42, 43, "foo", "bar", 44, 45, "baz", "fuu"]
p an_array_of_tuples(an_array, Tuple(Int32, Int32, String, String))

Note that you have to specify what types you want in the tuple, there’s no other way around that.

Hmm? It seems like it can be done simpler with just Tuple.from; your approach seems to just combine the two parts of the task with an “inlined” copy of it.

Ah but @asterite managed to avoid creating temporary arrays, that’s the advantage / tradeoff vs code simplicity

Yeah, I thought about Tuple.from but I would need a sub-array for that.

Regardless of this particular request, it would be nice if you could do something like array.each_slice!(3) where each thing yielded to the block was a tuple. Something like having that 3 available at compile-time for inspection. I guess you can do Array.each_slice(array, 3) and have that be a macro…

I like both solutions, thanks a lot!!