Can I use index to get a set element in Ruby? - 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

Related

How to remove duplicate pair values from given array in Ruby?

I want to remove a pair of 'duplicates' from an array of strings, where each element has the form R1,R2, with varying numbers. In my case, a duplicate would be R2,R1 because it has the same elements of R1,R2 but inverted.
Given:
a = ['R1,R2', 'R3,R4', 'R2,R1', 'R5,R6']
The resulting array should be like so:
a = ['R1,R2', 'R3,R4', 'R5,R6']
How could I remove the duplicates so I would have the following?
A solution with Set
require 'set'
a.uniq { |item| Set.new(item.split(",")) } # => ["R1,R2", "R3,R4", "R5,R6"]
Here is a working example :
array = ['R1,R2', 'R3,R4', 'R2,R1', 'R5,R6']
array.uniq { |a| a.split(',').sort }
try this,
def unique(array)
pure = Array.new
for i in array
flag = false
for j in pure
flag = true if (j.split(",").sort == i.split(",").sort)
end
pure << i unless flag
end
return pure
end
reference: https://www.rosettacode.org/wiki/Remove_duplicate_elements#Ruby
If the elements of your array are "pairs", they should maybe be actual pairs and not strings, like this:
pairs = [['R1', 'R2'], ['R3', 'R4'], ['R2', 'R1'], ['R5', 'R6']]
And, in fact, since order doesn't seem to matter, it looks like they really should be sets:
require 'set'
sets = [Set['R1', 'R2'], Set['R3', 'R4'], Set['R2', 'R1'], Set['R5', 'R6']]
If that is the case, then Array#uniq will simply work as expected:
sets.uniq
#=> [#<Set: {"R1", "R2"}>, #<Set: {"R3", "R4"}>, #<Set: {"R5", "R6"}>]
So, the best way would be to change the code that produces this value to return an array of two-element sets.
If that is not possible, then you should transform the value at your system boundary when it enters the system, something like this:
sets = a.map {|el| el.split(',') }.map(&Set.method(:new))

How can I pop an element from a Set in 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

Ruby Building an Array

Argh. Having trouble here trying to work out how to build my array in Ruby.
So I am looping through a result and I want to add the category field as the key and have it so that if the next row has the same category it gets put into that category. If not, it makes a new array and adds it to that.
Here is what I have so far.
data = Array.new
results.each do |row|
data[row.category].push row.field
end
Which is not going to work I know. I want data[row.category] to eventually be (after the loop) an array containing all the row.field's
So I end up with an array that looks like this.
[['Dogs', 5, 12, 2], ['Cats', 4, 5, 9], ['Fish', 25, 82, 23]]
So no matter how many loops I do, if I push it into an array that already exists in data then it just appends it, if the array doesn't exist it creates it and then appends it.
In PHP I would simply do this:
$data[$row['category']][] = $row['field']
With the empty [] denoting to create a new array if there is none. How do I do this in Ruby???
Yeah, you seem to be confused by PHP and its associative arrays (which aren't called arrays in any other language :) ). You need a hash. Try this snippet:
data = results.each_with_object({}) do |row, memo|
memo[row.category] ||= [] # create array unless it exists
memo[row.category] << row.field
end
Unlike PHP, you cannot use any object as index for an Array. In Ruby, we use Hashes to associate arbitrary objects with other objects.
Your code should work if you change it to:
data = Hash.new { |hash, key| hash[key] = [] }
results.each do |row|
data[row.category] << row.field
end

Ruby: Selecting a set of array indices whose elements pass a test

Ruby has a select method that takes an array and returns a subarray consisting of all the elements that pass the test given in a block:
myarray.select{|e| mytest(e)} #=> subarray of elements passing mytest
I am wondering whether there is a simple method to get not these elements, but their indices. I understand you could do this:
indices = []
myarray.each_with_index{|e,i| indices << i if mytest(e)}
But I'm looking for a one-liner. Does one exist? Please don't write an extension to the Array class, I know you can get a one-liner that way.
Another one-liner:
(0...myarray.length).select {|i| mytest(myarray[i])}
Cheers!
Here's a one-liner for you. It selects indexes of elements whose length is 3.
a = ['foo', 'bar', 't']
a.map.with_index{|el, i| i if el.length == 3}.compact # => [0, 1]
Or another one (suggested by #fl00r):
a.reduce([]){|ar,el| ar << a.index(el) if el.size == 3; ar}
Also,
myarray.select{|e| mytest(e)}.map!{|e| myarray.index(e)}
However, this won't work properly if you have any repeated elements.

Ruby: hash that doesn't remember key values

Is there a hash implementation around that doens't remember key values? I have to make a giant hash but I don't care what the keys are.
Edit:
Ruby's hash implementation stores the key's value. I would like hash that doesn't remember the key's value. It just uses the hash function to store your value and forgets the key. The reason for this is that I need to make a hash for about 5 gb of data and I don't care what the key values are after creating it. I only want to be able to look up the values based on other keys.
Edit Edit:
The language is kind of confusing. By key's value I mean this:
hsh['value'] = data
I don't care what 'value' is after the hash function stores data in the hash.
Edit^3:
Okay so here's what I am doing: I am generating every 35-letter (nucleotide) kmer for a set of multiple genes. Each gene has an ID. The hash looks like this:
kmers = { 'A...G' => [1, 5, 3], 'G...T' => [4, 9, 9, 3] }
So the hash key is the kmer, and the value is an array containing IDs for the gene(s)/string(s) that have that kmer.
I am querying the hash for kmers in another dataset to quickly find matching genes. I don't care what the hash keys are, I just need to get the array of numbers from a kmer.
>> kmers['A...G']
=> [1, 5, 3]
>> kmers.keys.first
=> "Sorry Dave, I can't do that"
I guess you want a set, allthough it stores unique keys and no values. It has the fast lookup time from a hash.
Set is included in the standard libtrary.
require 'set'
s = Set.new
s << 'aaa'
p s.merge(['ccc', 'ddd']) #=> #<Set: {"aaa", "ccc", "ddd"}>
Even if there was an oddball hash that just recorded existence (which is how I understand the question) you probably wouldn't want to use it, as the built-in Hash would be simpler, faster, not require a gem, etc. So just set...
h[k] = k
...and call it a day...
I assume the 5 gb string is a genome, and the kmers are 35 base pair nucleotide sequences.
What I'd probably do (slightly simplified) is:
human_genome = File.read("human_genome.txt")
human_kmers = Set.new
human_genome.each_cons(35) do |potential_kmer|
human_kmers << potential_kmer unless human_kmers.include?(potential_kmer)
end
unknown_gene = File.read("unknown_gene.txt")
related_to_humans = unknown_gene.each_cons(35).any? do |unknown_gene_kmer|
human_kmers.include?(unknown_gene_kmer)
end
I have to make a giant hash but I don't care what the keys are.
That is called an array. Just use an array. A hash without keys is not a hash at all and loses its value. If you don't need key-value lookup then you don't need a hash.
Use an Array. An Array indexes by integers instead of keys. http://www.ruby-doc.org/core/classes/Array.html
a = []
a << "hello"
puts a #=> ["hello"]

Resources