array question

E

Edwin Fine

And a more efficient solution (thanks to Reid Morrison) is

array_new = (1..array.length - 2).inject([]) {|arr, i| arr << array
<< array}
 
L

Louis J Scoras

Need to take care of size == 1

class Array
def duplicate_internal
return self if size == 1 # added
to_enum:)each_cons,2).inject([]) do |r, c|
r + c
end
end
end
 
J

Joel VanderWerf

Hi --

Sorry missed a brace on the block. Should be

b = a.inject( [] ) { |a,e| a << [e,e]}.flatten[1..-2] }

I so much think it's time for flatten to take an argument, specifying
number of levels to flatten. My flattenx extension does this, and it
seems like a natural fit for flatten itself. Otherwise almost all
flatten-based techniques run the risk of over-flattening.

100% agreement here. The problem is easily solved if you ignore the
flattening risk:

a = (1..5).to_a
p a[0..-2].zip(a[1..-1]).flatten
# ==> [1, 2, 2, 3, 3, 4, 4, 5]

The inject solution is a little less elegant and probably much less
efficient:

p a[0..-2].zip(a[1..-1]).inject{|s,x| s+x}
# ==> [1, 2, 2, 3, 3, 4, 4, 5]

Maybe a little more efficient:

p a[0..-2].zip(a[1..-1]).inject{|s,x| s.concat x}


I've gotten out the the habit of using #zip for exactly this reason: you
have to flatten the output to get what you really want, but then you
might get something you really don't want.
 
D

dblack

Hi --

I'm surprised nobody has suggested:

a.zip(a).flatten[1..-2]

I decided to avoid flatten (see my earlier comments). To be
flatten-safe, you could do:

require 'flattenx' # [1]
a.zip(a).flatten_once[1..-2]


David

[1] http://www.rubypal.com/ruby/flattenx

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
P

Peña, Botp

Pete Yandell [mailto:p[email protected]] :
# I'm surprised nobody has suggested:
# a.zip(a).flatten[1..-2]

indeed. that's a nice surprise. thanks for the tip.
kind regards -botp
=20
# Cheers,
# Pete Yandell
#=20
#=20
 
D

Daniel Schierbeck

I'm surprised nobody has suggested:

a.zip(a).flatten[1..-2]

I'm surprised nobody has suggested

require 'enumerator'

ary.enum_cons(2).entries.flatten


Cheers,
Daniel
 
D

dblack

Hi --

Li said:
Hi all,

I want to build a new array from an old one with every element being
duplicated except the first and last element. And here are my codes. I
wonder if this is a real Ruby way to do it.
array=[1,2,3,4,5,6,7,8,9,10] => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
array.zip(array).flatten[1..-2]
=> [1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10]

I *still* don't feel comfortable with that one :) The flatten
thing is just too fragile.


David

--
David A. Black | (e-mail address removed)
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] http://www.manning.com/black | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org
 
E

Edwin Fine

I benchmarked the various suggestions and added some of my own, and the
results may surprise some (they surprised me!)

Rehearsal --------------------------------------------------------------
:zip_flatten_technique 8.280000 0.000000 8.280000 ( 19.532383)
:enum_cons_technique 18.190000 0.020000 18.210000 ( 28.552418)
:copy_inject_technique 5.500000 0.000000 5.500000 ( 5.567597)
:fill_technique 5.250000 0.010000 5.260000 ( 5.373526)
:naive_technique 5.040000 0.000000 5.040000 ( 5.091017)
:flatten_compact_technique 7.900000 0.000000 7.900000 ( 7.938109)
:eek:riginal_technique 2.560000 0.000000 2.560000 ( 2.620933)
:zip_concat_technique 6.480000 0.000000 6.480000 ( 6.493874)
---------------------------------------------------- total: 59.230000sec

user system total real
:zip_flatten_technique 7.500000 0.000000 7.500000 ( 7.636382)
:enum_cons_technique 17.790000 0.680000 18.470000 ( 18.536960)
:copy_inject_technique 5.250000 0.000000 5.250000 ( 5.277144)
:fill_technique 5.070000 0.010000 5.080000 ( 5.165221)
:naive_technique 5.100000 0.010000 5.110000 ( 5.113858)
:flatten_compact_technique 7.330000 0.000000 7.330000 ( 7.350595)
:eek:riginal_technique 2.590000 0.000000 2.590000 ( 2.600783)
:zip_concat_technique 6.190000 0.000000 6.190000 ( 6.197641)

So the OP's technique, if not the prettiest, is actually by far the
fastest, and is correct when used with nested arrays. Some of the other
solutions (that use flatten) are incorrect when used with nested arrays.

Here's the code:

require 'benchmark'
require 'enumerator'

techniques = {
:enum_cons_technique => lambda {|arr|
arr.enum_cons(2).inject([]) {|a, i| a+i}},
:zip_flatten_technique => lambda {|arr|
arr.zip(arr).flatten[1..-2]},
:copy_inject_technique => lambda {|arr| copy = [];
arr.inject{|a,b| copy << a << b; b}; copy},
:flatten_compact_technique => lambda {|arr|
arr.zip(arr[1...-1]).flatten!.compact!},
:zip_concat_technique => lambda {|arr| arr.zip(arr).inject([])
{|n, e| n.concat(e)}[1..-2]},
:fill_technique => lambda {|arr| (Array.new((arr.length <<
1) - 2) {|i| arr[i >> 1]})[1..-2]},
:naive_technique => lambda do |arr|
a = Array.new((arr.length * 2) - 2)
a[0] = arr.first
a[a.length - 1] = arr.last
n = 1
1.upto(arr.length - 2) {|i| a[n] =
a[n+1] = arr; n += 2}
a
end,
:eek:riginal_technique => lambda do |arr|
array_new = Array.new
arr.each {|e| array_new << e << e}
array_new.delete_at(0)
array_new.delete_at(array_new.size -
1)
array_new
end
}

n = 5000
array = ["a", 2, (0..1), /^$/, 1.2345, ["arr"] ] * 100

Benchmark.bmbm do |x|
techniques.each do |name, proc|
x.report(name.inspect) { n.times { proc.call(array) } }
end
end
 
L

Li Chen

So the OP's technique, if not the prettiest, is actually by far the
fastest, and is correct when used with nested arrays. Some of the other
solutions (that use flatten) are incorrect when used with nested arrays.

What is meaning for OP here?

Thanks,

Li
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,780
Messages
2,569,611
Members
45,276
Latest member
Sawatmakal

Latest Threads

Top