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

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.