The Crystal Programming Language Forum

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.

2 Likes

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.

1 Like

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!!