David Alan Black <dblack / candle.superlink.net> wrote:
> Hello --
> 
> Is there a nice Ruby idiom for interleafing arrays?  It's not hard to
> write a method that will do it, but I'd be interested in knowing how
> it's been done in the past.

What do you mean by interleave?  Normally I'd take this to mean that you'd 
want the even number of elements from the first array and the odd numbered 
elements to come from the second array, but it seems you're implying you 
just want the logical union of the two.  e.g.

irb(main):004:0> ["ichi", "ni", "san"] | ["san", "yon", "go"]
["ichi", "ni", "san", "yon", "go"]

Which you can also do with (A + B).uniq, or destructively with 
A.join(B).uniq!.

If you mean that you want to actually want to interleave the elements, I can 
think of a bunch of ways, but no actual idiom.  One would be:

irb(main):042:0> class Array
irb(main):043:1>     def interleave(ary2)
irb(main):044:2>         ary1 = self.reverse
irb(main):045:2>         ary2 = ary2.reverse
irb(main):046:2>         nary = []
irb(main):047:2>         flipflop = true
irb(main):048:2>         while !ary1.empty? && !ary2.empty?
irb(main):049:3>             nary.push((flipflop ? ary1 : ary2).pop)
irb(main):050:3>             flipflop = !flipflop
irb(main):051:3>         end
irb(main):052:2>         nary.concat((ary2.empty? ? ary1 : ary2).reverse)
irb(main):053:2>         return nary
irb(main):054:2>     end
irb(main):055:1> end
nil
irb(main):056:0> [1, 3, 5, 7, 8, 9].interleave([2, 3, 4, 6])
[1, 2, 3, 3, 5, 4, 7, 6, 8, 9]
irb(main):057:0> [1, 3, 5, 7, 8, 9].interleave([2, 4, 6])
[1, 2, 3, 4, 5, 6, 7, 8, 9]

> By the way, my curiosity about this stems from some tinkering with
> hashes -- specifically, trying to populate a hash from two arrays.  A
> related problem, which I'll throw in here too, is how best to create a
> hash which simply sets each value to "true" (or 1, or whatever).  The
> best I've come up with for that is:
> 
>    h = Hash[*arr.map { |x| [x,true] } .flatten ]
> 
> which feels awfully roundabout for this purpose.  Intervention
> is welcome.

You can always do it as:

h = Hash.new(false)
(array1 + array2).each {|x| h[x] = true}

This version seems slightly less "functional", but it should be more 
efficient, and it's less convoluted.  In this case, I'd be inclined to 
believe that using the or operator | instead of + would be a bit slower.
I suppose if I _really_ cared about making it totally functional, I could
do something evil ;):

[Hash.new(false)].each {|h| (array1 + array2).each {|x| h[x] = true}}

> Thanks --
> 
> 
> David

Hope this helps.

--
 Brian Fundakowski Feldman           \  FreeBSD: The Power to Serve!  /
 green / FreeBSD.org                    `------------------------------'