Using Tuples in Ruby?
Asked Answered
F

7

82

Does anyone use tuples in Ruby? If so, how may one implement a tuple? Ruby hashes are nice and work almost as well, but I'd really like to see something like the Tuple class in Python, where you can use . notation to find the value for which you are looking. I'm wanting this so that I can create an implementation of D, similar to Dee for Python.

Feleciafeledy answered 8/2, 2009 at 16:11 Comment(5)
Did you ever implement D in Ruby? If so, do you have the link to it? I've been working on something similar recently, and I'd love to see what you've done so far.Spence
Nope; I never made it that far. I've been winding my way around several other things trying to get back to it. I did find several libraries that seem as though they would help: LazyList and arel. I basically came to the conclusion that LINQ in .NET was almost there, then found arel, which was also close. Using LazyList and removing the direct-to-SQL conversion, the latter of which is also a project goal, would almost get you there. That said, I would love to see what you have so far. I'm still a little way off from getting back to it.Feleciafeledy
ambition is another interesting looking library, but it hasn't been updated in some time. That was the one I found first. arel looks like it has continued in the same tradition.Feleciafeledy
I've just begun a project called veritas to work on this: github.com/dkubb/veritas It's still really early. If things go well I may update DataMapper to use it as a foundation. I'm not really interested in supporting Ambition-like syntax in the core, since you can only use ParseTree with 1.8, but I wouldn't have a problem with a plugin like the one I wrote for DataMapper: github.com/dkubb/dm-ambitionSpence
I should add that I'm considering updating the underlying implementation to use Struct objects for the tuples to optimize memory usage, but at the moment I'm more concerned about correctness and speccing out the public API.Spence
P
59

OpenStruct?

Brief example:

require 'ostruct'

person = OpenStruct.new
person.name    = "John Smith"
person.age     = 70
person.pension = 300

puts person.name     # -> "John Smith"
puts person.age      # -> 70
puts person.address  # -> nil
Pearl answered 8/2, 2009 at 16:23 Comment(6)
np :) to answer you question though: no i do not use tuples in ruby, as openstructs or otherwise. i use classes at the high end and hashes at the low end :)Pearl
this is a poor answer, just a link? Seriously? what happens if/when the link becomes broken?Canker
it's not even the notion of Tuple you expose here. Just a data structure. Can't understand how your solution is the most upvotedRookery
@JulesIvanic valid comment but sometimes an OP does not know how to properly formulate a title for a question, in this case this is actually the answer that the OP is looking for :)Electroballistics
I know this question has been edited to have a proper answer, but I'd just like to acknowledge that the link is now broken.Jumbala
@Pieter-JanBriers - fixed. Hopefully fairly permanently, though of course only time will tell.Indicator
T
36

Based on the fact that you talk about hashes and . notation I'm going to assume you mean a different kind of tuple than the (1. "a") sort. You're probably looking for the Struct class. eg:

Person = Struct.new(:name, :age)
me = Person.new
me.name = "Guy"
me.age =  30
Tenorite answered 8/2, 2009 at 16:26 Comment(4)
That's close, but having to name it bugs me. I was looking for something like the (1. "a") sort but with the property get/set notation you describe.Feleciafeledy
@panesofglass, there's no need to name nothing: a = Struct.new(:name, :age).new; a.name = "Guy"Evanesce
Can I set a = Struct.new(:name, :age) and later say a.new? I would suppose so. I'll have to check that out. It would be a lot more explicit as to what I want.Feleciafeledy
Finding this years later, I can confirm that Person.new("Guy", 30) does work in addition to setting the fields individually.Kelantan
C
20

While this isn't strictly a tuple (can't do dot notation of members), you can assign a list of variables from a list, which often will solve issues with ruby being pass-by-value when you are after a list of return values.

E.g.

:linenum > (a,b,c) = [1,2,3]
:linenum > a
  => 1
:linenum > b
  => 2
:linenum > c
  => 3
Carriole answered 30/4, 2014 at 2:13 Comment(0)
T
17

Arrays are cool to use as tuples because of destructuring

a = [[1,2], [2,3], [3,4]]
a.map {|a,b| a+b }

Struct give you convenient . accessors

Person = Struct.new(:first_name, :last_name)
ppl = Person.new('John', 'Connor')
ppl.first_name 
ppl.last_name

You can get the convenience of both worlds with to_ary

Person = Struct.new(:first_name, :last_name) do
  def to_ary
    [first_name, last_name]
  end
end
# =>
[
  Person.new('John', 'Connor'), 
  Person.new('John', 'Conway')
].map { |a, b| a + ' ' + b  }
# => ["John Connor", "John Conway"]
Telophase answered 5/2, 2020 at 21:53 Comment(0)
S
11

I'm the author of Gem for Ruby tuples.

You are provided with two classes:

  • Tuple in general
  • Pair in particular

You can initialize them in different ways:

Tuple.new(1, 2)
Tuple.new([1, 2])
Tuple(1, 2)
Tuple([1, 2])
Tuple[1, 2]

Both of the classes have some auxiliary methods:

  • length / arity - which returns number of values inside tuple
  • first / last / second (only pair) - which returns a corresponding elements
  • [] that gives you an access to a particular elements
Symbolics answered 12/6, 2015 at 5:51 Comment(1)
What is the difference between all the initializers? Or are they all equivalent? (which I suppose) If known from functional programming, which would be an examplary language that uses this syntax?Otis
R
8

You can mock the Scala tuples with this trick :

Tuple = Struct.new(:_1, :_2)

2.2.5 :003 > t = Tuple.new("a", "b")
 => #<struct Tuple _1="a", _2="b">
2.2.5 :004 > t._1
 => "a"
2.2.5 :005 > t._2
 => "b"

but here you can't have destructuring:

2.2.5 :012 > a, b = t
 => {:_1=>"a", :_2=>"b"}
2.2.5 :013 > a
 => {:_1=>"a", :_2=>"b"}
2.2.5 :014 > b
 => nil

But thanks to this trick : https://gist.github.com/stevecj/9ace6a70370f6d1a1511 destructuring will work:

2.2.5 :001 > Tuple = Struct.new(:_1, :_2)
 => Tuple
2.2.5 :002 > t = Tuple.new("a", "b")
 => #<struct Tuple _1="a", _2="b">
2.2.5 :003 > t._1
 => "a"
2.2.5 :004 > class Tuple ; def to_ary ; to_a ; end ; end
 => :to_ary
2.2.5 :005 > a, b = t
 => #<struct Tuple _1="a", _2="b">
2.2.5 :006 > a
 => "a"
2.2.5 :007 > b
 => "b"
Rookery answered 6/12, 2016 at 15:14 Comment(1)
This could be made a little less confusing by simply defining the destructing accessor method in a block passed to Struct.new like ghostbin.com/paste/vwtg6Vigilante
S
3

You can do something similiar with destructuring:

def something((a, b))
  a + b
end

p something([1, 2])

This prints out 3 as expected.

Straley answered 26/5, 2015 at 9:7 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.