2

I have arrays and nested arrays, such that:

a = [1,2]
b = [[3,4],[5,6]]
c = [7,8]

What's the best way to create

d = [[1,2],[3,4],[5,6],[7,8]]

in Ruby?

UPDATE:

The goal is to create a method below:

def foo([a,b,c])
  --some logic that iterates through each array--
end
5
  • 1
    Simplest would be [a] + b + [c], but I believe you need more general solution? Commented Mar 26, 2014 at 21:20
  • Yes please. I will add to the original post. Commented Mar 26, 2014 at 21:21
  • Need some more clarification - what is to happen if for example a = [1] or a = [[1,2], 'hello'] Commented Mar 26, 2014 at 21:25
  • Why the rush to select an answer? Consider waiting awhile in future. A quick selection tends to discourage additional, possibly better, answers. Commented Mar 26, 2014 at 22:45
  • Cary, thanks, I'm just realizing that now :). This is the first time a question I raised has actually elicited more than one response. Definitely have learned my lesson. Commented Mar 27, 2014 at 0:00

6 Answers 6

3
def foo(xss)
  xss.flat_map { |xs| xs.first.is_a?(Array) ? xs : [xs] }
en

foo([a, b, c]) #=> [[1, 2], [3, 4], [5, 6], [7, 8]]
Sign up to request clarification or add additional context in comments.

1 Comment

Probably the best solution, flat_map is way faster than most of the other methods out there.
1

This will work assuming inputs are always arrays. Might have some side effects if any input is formatted differently.

def foo(*args)
  args.map {|a| a.first.is_a?(Array) ? a : [a]}.inject([], :+)
end

foo([1,2], [[3,4],[5,6]], [7,8])    #=>  [[1, 2], [3, 4], [5, 6], [7, 8]]

4 Comments

Thank you! I will accept this answer because it is a bit more readable then Arup's. Optional question to you: is there a way to implement something like [a, b.each{|b| b}, c]?
I hadn't seen this, which is basically my answer. Note though that you shouldn't concat arrays using inject, it's very inefficient O(n^2). Use flat_map instead.
@tokland - Could you explain - I always thought inject is O(n). Is array addition O(n) as well or am I missing sth else?
Enumerble#inject is O(n) but the inner operation Array#+ is also O(n), so the total is O(n^2). That's because Array#+ creates a new array. With an in-place update, it would be O(n): xss.reduce([], :concat).
1
def foo(a,b,c)
  final = []

  a.first.is_a?(Array) ? a.each { |x| final << x } : final << a
  b.first.is_a?(Array) ? b.each { |x| final << x } : final << b
  c.first.is_a?(Array) ? c.each { |x| final << x } : final << c

  final
end

1 Comment

Perhaps you could add a little explanation as to how this should solve the problem, rather than just posting some code?
1

I'd do :

a = [1,2]
b = [[3,4],[5,6]]
c = [7,8]

final_ary = [a,b,c].inject([]) do |out_ary,ary| 
  if ary.first.is_a?(Array)
    out_ary.concat(ary)
  else
    out_ary.push(ary)
  end
end

final_ary
# => [[1, 2], [3, 4], [5, 6], [7, 8]]

Comments

1
def foo (*args)
  args.flatten.each_slice(2).to_a
end

foo(a,b,c) # => [[1, 2], [3, 4], [5, 6], [7, 8]]

2 Comments

If b is b = [[3,4],[5,6,7]] ? :-)
No.. problem.. Go ahead :-)
0

A general solution:

def extract(arr, result=[])
  return result if arr.empty?
  arr.each {|e| (e.first.is_a? Array) ? result=extract(e,result) : result << e}
end

p extract( [ [1,2],[3,4,5],[6,7] ] )
  #=> [[1, 2], [3, 4, 5], [6, 7]]
p extract( [ [1,2],[ [3,4],[5,6] ],[7,8]] )
  #=> [[1, 2], [3, 4], [5, 6], [7, 8]] 
p extract( [ [1,2],[ [3,4],[ [5,6],[7,8] ] ],[9,10,11] ] )
  #=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10, 11]]
p extract( [ [1,2],[ [3,4],[ [5,6],[ [7,8],[9,10] ] ] ],[11,12] ])
  #=> [[1, 2], [3, 4], [5, 6], [7, 8], [9, 10], [11, 12]] 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.