From: "Brian F. Feldman" Date: 2000-11-27T06:36:39+09:00 Subject: [ruby-talk:6583] Re: best way to interleaf arrays? David Alan Black 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 `------------------------------'