Confusion
Confusion

Reputation: 16841

Take and remove elements from a Ruby Set in one operation

I have a Set of elements from which I want to take and remove the first few elements a bunch of times. Is there a shorter way (so one operation instead of two) to do that than this:

require 'set'
s = Set[1, 2, 3, 4]       # => #<Set: {1, 2, 3, 4}> 

first_two = s.take(2)     # => [1, 2]
s.subtract(first_two)     # => #<Set: {3, 4}>

(So basically I'm wondering whether I'm overlooking a shift for Sets)

Upvotes: 5

Views: 3723

Answers (4)

ichigolas
ichigolas

Reputation: 7725

From http://www.ruby-doc.org/stdlib-1.9.3/libdoc/set/rdoc/Set.html:

Set implements a collection of unordered values with no duplicates. This is a hybrid of Array's intuitive inter-operation facilities and Hash's fast lookup.

It would be odd and probably illogical to implement methods like shift and pop on an object that knows nothing about index.

Upvotes: 1

Marc-Andr&#233; Lafortune
Marc-Andr&#233; Lafortune

Reputation: 79562

There is no shorter way using builtin methods.

There is an open feature request for a method to return and remove one element; you may want to help refine the API?

Upvotes: 3

manu3569
manu3569

Reputation: 183

I'm late to the party, but here's my solution. Convert the set to an array first, and then all Enumerable methods are available. Take 2 from the array and then be sure to also remove the from the set. The two values from the set get removed and returned.

require 'set'
s = Set[1, 2, 3, 4]     # => #<Set: {1, 2, 3, 4}> 

first_two = s.to_a.take(2).tap {|a| s.subtract(a)}  # => [1, 2]
s                       # => #<Set: {3, 4}>

Upvotes: 0

Conkerchen
Conkerchen

Reputation: 740

You could add a new method take! (or remove! or whatever name seems appropriate) to the Set class:

class Set
  def take!(args)
    taken = self.take(args)
    self.subtract(taken)
    return taken
  end
end

a = Set[1, 2, 3, 4] # <Set: {1, 2, 3, 4}>
a.take!(2) # <Set: {1, 2}>
a # <Set: {3, 4}>

Upvotes: 5

Related Questions