Forum: Ruby a, b, c, d = .map{|x| x + o}

8e16f7669af5b4ecfa4f2b89f32b21b6?d=identicon&s=25 Stefan Salewski (Guest)
on 2013-11-07 01:14
(Received via mailing list)
I am doing some calculations, which often includes adding some offset to
a few values, i.e. moving a line segment (x1, y1, x2, y2).
Storing the values in an array makes not really sense, I don't want to
write coord[0][1] instead of y1.

So I have a few statements like

a, b, c, d = a + o, b + o, c + o, d + o

I can replace that with

a, b, c, d = [a, b, c, d].map{|x| x + o}

which is slower, but "cleaner" in my opinion.
Is there another solution?
3df767279ce7d81db0a5bb30f5136863?d=identicon&s=25 Matthew Kerwin (mattyk)
on 2013-11-07 02:22
Stefan Salewski wrote in post #1126646:
> I am doing some calculations, which often includes adding some offset to
> a few values, i.e. moving a line segment (x1, y1, x2, y2).
> Storing the values in an array makes not really sense, I don't want to
> write coord[0][1] instead of y1.
>
> So I have a few statements like
>
> a, b, c, d = a + o, b + o, c + o, d + o
>
> I can replace that with
>
> a, b, c, d = [a, b, c, d].map{|x| x + o}
>
> which is slower, but "cleaner" in my opinion.
> Is there another solution?

I think there's nothing wrong with writing

  a += o
  b += o
  c += o
  d += o

as an alternative to the first statement, it lines up vertically and
it's clear on a row-by-row basis what is happening to each variable;  it
depends entirely on your tastes.

Anything you do to write it more succinctly will almost certainly be
slower.

If ruby were more of a lisp, I could imagine that something like this
could be optimised in the compiler:

  (a, b, c, d).map!{|x| x + o }

but it's not, and it isn't.

Edit:  here's a hacky hack, playing with this idea:
https://gist.github.com/phluid61/7347383
09a32175057418748822c587ac08c429?d=identicon&s=25 Abinoam Jr. (abinoampraxedes_m)
on 2013-11-07 02:57
(Received via mailing list)
Considering the slower approachs they could lead you to a code like this
...

class Point
  def initialize(x,y)
    @x, @y = x, y
  end

  def self.[](x,y)
     new(x,y)
  end

  def +(offset)
     @x += offset
     @y += offset
  end
end

p1 = Point[10,20]
p2 = Point[30,40]

[p1, p2].each { |p| p += 1}

Or you can go futher writing a class called PointCollection ...

And have something like ...

pc = PointCollection.new(p1, p2)

pc.increment_all_by(1)

And you can go on... to infinite and beyond...

But, I think your first example is just right (since you use it with
only 4 variables (not 100)).

Abinoam Jr.
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (robert_k78)
on 2013-11-07 13:11
(Received via mailing list)
On Thu, Nov 7, 2013 at 2:56 AM, Abinoam Jr. <abinoam@gmail.com> wrote:
> Considering the slower approachs they could lead you to a code like this ...

I agree to the approach to create a specific class for coordinates.

>      @x += offset
>      @y += offset
>   end

That's a bad implementation.  To start with this method should return
a Point.  Then, modifying in place does not fit well with how Ruby
handles operators. And handling of argument types is also not in line
with what Ruby does. I blogged about this a while ago:
http://blog.rubybestpractices.com/posts/rklemme/01...

I'd rather have a method "move" which does the transformation:

def move(delta)
  @x += delta
  @y += delta
  self
end

> end

You can achieve the same by

Point = Struct.new :x, :y

(apart from operator + of course).

Kind regards

robert
09a32175057418748822c587ac08c429?d=identicon&s=25 Abinoam Jr. (abinoampraxedes_m)
on 2013-11-07 15:52
(Received via mailing list)
> def move(delta)
>   @x += delta
>   @y += delta
>   self
> end

+1 to Robert Klemme (and to the blog post)
Please log in before posting. Registration is free and takes only a minute.
Existing account

NEW: Do you have a Google/GoogleMail, Yahoo or Facebook account? No registration required!
Log in with Google account | Log in with Yahoo account | Log in with Facebook account
No account? Register here.