How can I pop an element from a Set in Ruby? - ruby

In Python I can do a_set.pop() and I remove an element from the set and catch it in a variable. Is there a way to do the same thing with a set in Ruby?

The best way to research a question like this is to look at the docs. A Google search for 'ruby set' will help you to find the doc for the ruby Set class. You can then review all of the available instance methods.
As you can see, a Set is "a collection of unordered values with no duplicates." Since it's unordered, it's not designed to get values at particular locations within the set, including the last value.
You could convert to an array using #to_a and then use #pop on the array, but since the order of a Set is not guaranteed, you might not end up with the value you're expecting.
Edit: Interestingly, pop in Python deletes and returns "an arbitrary element." I see now that that's what you were looking for. While this is not available as a built-in method in a Ruby set, I suppose you could implement it using Array#sample, which grabs a random element from an array, and then delete it from the Set:
class Set
def pop
el = self.to_a.sample
self.delete(el)
el
end
end

Ruby Set haven't pop method, but you can do like this:
class Set
def pop
temp = self.to_a.pop
self.delete(temp)
temp
end
end
s1 = Set.new [1, 2]
=> #<Set: {1, 2}>
s1.pop
=> 2
s1
=> #<Set: {1}>

pop should always mean popped off the stack. A stack is last-in-first-out. That to me would mean that
1) The set should be ordered
2) The last element added is the one that gets popped
My implementation would be:
class Set
def pop
element = to_a.last
delete(element)
element
end
end

If you just want any element of the set returned, this will work.
class Set
def pop
popped = first
delete(first)
popped
end
end

Related

Can I use index to get a set element in Ruby?

Suppose I have a set in Ruby s1:
#<Set: {12, 25}>
I use s1.find_index(12) to get the index 0
Can I use the index to get back the set element, something like s1[0] to get back 12?
The reason I want to do this is my set elements are large. I want to store links between the set elements. I use the index to store the links.
I am using Ruby 1.9.3
I think you want to use an Array and a Hash for this.
ary = []
hsh = {}
unless hsh[item]
hash[item] = ary.size
ary << item
end
Then when you look up the item in hsh later you will have the index of the item in the list and effectively you will have the internals of your set with a specific caveat
That might not be possible. Set is an unordered list.
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.
You can get an element from a set by its index in this way:
my_set = Set.new([1, 4, 7])
if index = my_set.find_index(4)
puts my_set.to_a[index]
end

Ruby passing arguments: difference between Array and Set

I'm trying to put an array to another existing array and moreover to put all its items to an existing set. Here's the minimal example:
require "set"
def add(myarr, bigarr, myset)
bigarr << myarr
myset |= Set.new(myarr)
end
bigarr = []
myset = Set.new
add([1, 2], bigarr, myset)
Which yields bigarr = [1, 2] .. OK, but myset = {} .. is empty. I know little about passing arguments in Ruby (should be by-value) -- in case of array the value should be a reference to its content, then I have no clue what could be the value of set.
The questions are:
What is the substantial difference between Array and Set which causes this behavior?
Is there any way to force Ruby pass-by-reference or is there a different recommended way how to solve the problem with referencing?
Thanks in advance!
This doesn't have anything to do with the difference between arrays and sets. You're modifying the array with the << method, but you're reassigning the myset variable with the |= operator. You never modify the set you passed in. What you want is probably myset.merge(myarr).
The problem here actually comes from this particular line:
myset |= Set.new(myarr)
Here you're creating new object on old variable name. You're replacing one pointer with another, however this only modifies local copy of it. Original object will still exists in memory and outside function, pointer will point to old object (empty set) (tbh: I would not really encourage this kind of writing in ruby with side effects).
If you change it to
require "set"
def add(myarr, bigarr, myset)
bigarr << myarr
myset.add(myarr)
end
bigarr = []
myset = Set.new
add([1, 2], bigarr, myset)
It's working properly - because you modify existing object and don't create new one.
There is great answer that goes more thoroughly into this, right here: https://stackoverflow.com/a/16464640/1975116

What's i in each_with_index block

Okay, so im reading a guide for ruby and I can't make sense of this code. Where did i come from. I see that n is passed to iterate through the block but I have no idea where I comes from. If I could get a full explanation and breakdown of how this code works that would be great!
class Array
def iterate!
self.each_with_index do |n, i|
self[i] = yield(n)
end
end
end
array = [1, 2, 3, 4]
array.iterate! do |n|
n ** 2
end
i is the index of the element (hence the name, each_with_index).
Some methods that are called with code blocks will pass more than one value to the block, so you end up with multiple block arguments (in your case the block arguments are n and i, which will hold the current item in the array (n) and the index of it (i)).
You can find out how many arguments a block will be passed by looking at the documentation for a method (here's the docs for each_with_index). It does look like the extra values come from nowhere at first, and it takes a little while to memorize what a block will be passed when different methods are called.
i is commonly used as what's known as an "iterative variable". Basically, the loop block that you've copied here goes through each "iteration" of the loop and uses a new value of i and assigns it to the variable n, which is then passed on to the operation at the second to last line. In this case, the new value is simply the next number in array, and so there are four iterations of the loop.

Checking for empty elements within my array - Ruby

I have an element in my array that when I print out the value of that specific element I get an empty value.
puts my_listing[2].inspect
[]
When I check to see if that specific element is empty, using empty? it returns true:
puts my_listing[2].empty?
true
But when I cycle through the entire array, checking to see if i is empty, it doesn't find that particular element.
my_listing.each do |i|
if i.empty?
puts i
end
end
i (in this case 2) is never printed to the screen.
Why is that?
Basically, I am trying to get rid of all the elements in the array that are empty (in this case the element at index 2) but I am not sure how to even get at those elements.
What am I missing?
Thanks.
You're not seeing anything printed because you forgot to use #inspect
You could also just have written:
my_listing.each do |i|
i.empty? and p i
end
To remove empty elements, you can do the following:
my_array = [[1],[2],[],[4]]
p my_array.reject(&:empty?) # => [[1], [2], [4]]
reject calls #empty? on all the elements and removes the ones which are empty
Oh please iterate like this
my_listing.each_with_index do |i,index|
if i.blank?
puts index.inspect
end
end
It give you index of array which will be empty or nil.

ruby: search an multi-dimensional array for a value and update if needed

Trying to look through an array and see if a particular value is set and if it is, update the numbers attached to it.
Example:
test = [['test',1,2],['watch',1,2],['fish',1,2]]
So I'd like to search this array for 'test' - if it exists, amend the values '1,2', if it doesn't exist, just add the new search term into the array.
New to ruby and having trouble searching inside a multi-dimensional array and getting the key back
I'd go for the hash method suggested in the comments, but if you're really wanting to store your data in the multidimensional array like that I suppose you could do something like:
search_term = "test"
search_item= nil
test.each do |item|
if item.include? search_term
search_item = item
end
end
if search_item.nil?
test << [search_term]
else
search_item << [1,2]
end
I think that would do it (although I'm a little fuzzy on what you were wanting to do after you found the item).

Resources