Find intersection of arrays - ruby-on-rails

I'm having trouble making a simple form that finds the intersection of two arrays. The end goal is to find the intersection of two arrays of emails, but right now i'm simply testing with integers. Everything works in the controller, and if I hard code the arrays in the view I get the correct result. Below is my code
Rails console, everything is kosher:
1.9.3p374 :011 > _a
=> [1, 2, 3, 4]
1.9.3p374 :012 > _b
=> [1, 2, 1, 1, 1]
1.9.3p374 :013 > c = _a & _b
=> [1, 2]
When I try pass the same values from a form, I get an empty array result (I'm passing both arrays into the view to ensure they're there.
Controller:
def intersect
#array1 = [params[:a]]
#array2 = [params[:b]]
#intersection = #array1 & #array2
end
Code in View:
Array 1: <%= #array1 %> <br>
Array 2: <%= #array2 %><br>
Intersection: <%= #intersection %>
Result in browser:
Array 1: ["1,2,3,4,5"]
Array 2: ["1,2,2,3,3"]
Intersection: []
Since I can get this to work hardcoded I'm sure i'm doing something newbish! Any help is beyond welcome!!!

Your arrays each contain a single element which is the string "1,2,3,4,5". You probably want an array with 5 elements instead ([1,2,3,4,5]). You can do so by splitting the array on a comma:
#array1 = params[:a].split(',')
#array2 = params[:b].split(',')
#intersection = #array1 & #array2
#=> ["1", "2", "3", "4", "5"]

Related

Filter Array in Ruby on Rails with only to_s elements

I have this code that works well
def self.select_some_elements(some_value)
return elements.select { |element| element.some_value > some_value}
end
This code returns an array of elements class instances/objects. However, I would like to return the array of element.to_s instances/propeties, not the whole class objects, just strings/string properties
Is there a quick way to do it without going extra steps?
Introduction:
So, what you have achieved is a set (array in this case) of objects, which is great. What you have to do now is to transform this set into a different one: namely, replace each object with what that object's method to_s returns. There's a perfect method for that, called map. It goes through all the items, calls a block with each item as an argument and puts in the resulting array what the block has returned:
Open irb console and play around:
>> [1,2,3].map{|x| 1}
=> [1, 1, 1]
>> [1,2,3].map{|x| x+1}
=> [2, 3, 4]
>> [1,2,3].map{|x| "a"}
=> ["a", "a", "a"]
>> [1,2,3].map{|x| x.to_s}
=> ["1", "2", "3"]
>> [1,2,3].map(&:to_s)
=> ["1", "2", "3"]
The last transformation seems to be what you need:
The answer:
Add .map(&:to_s) at the end like this
def self.select_some_elements(some_value)
return elements.select { |element| element.some_value > some_value}.map(&:to_s)
end
.map(&:to_s) is a short version of .map { |element| element.to_s }. And you can read about Arra3#map in the docs
And when you wrap your head around the #map, check out Stefan's answer which shows how select{}.map can be "compressed" into one filter_map call (doing both things: filter, and mapping in one iteration over the set instead of two).
Starting with Ruby 2.7 there's filter_map:
elements = [1, 2, 3, 4, 5]
elements.filter_map { |e| e.to_s if e > 2 }
#=> ["3", "4", "5"]

Remove array elements at indices non destructively

Let's say you have something like this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry']
I want to remove arbitrary entries by index from my_array without changing it and I want the filtered (i.e. array with indices removed) to be returned from my call. Furthermore, I want to avoid chaining 4 separate calls and write a block doing so.
Example:
filtered_array = my_array.drop_indices(1,3)
You could chain Enumerable's with_index onto Array's reject method to do what you want, though this might violate your desire to not chain separate method calls or write a block to do this:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
filtered = my_array.reject.with_index { |_, index| indices_to_remove.include?(index) }
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
If this isn't acceptable, the only other thing I can think of right now, to keep duplicate items (as noted in my comment to your solution), is to change from indices_to_remove to indices_to_keep:
my_array = ['some_rather', 'long_named', 'array_element', 'entry', 'long_named']
indices_to_remove = [1, 3]
indices_to_keep = [*(0...my_array.length)] - indices_to_remove
filtered = my_array.values_at(*indices_to_keep)
p filtered # => ["some_rather", "array_element", "long_named"]
p my_array # => ["some_rather", "long_named", "array_element", "entry", "long_named"]
For Arrays with duplicate Elements the best I know is:
array = [0,15,8,15,8]
indices_to_remove = [1,4]
res = array.reject.with_index{ |_,i| indices_to_remove.include?(i) }
returns
[0,8,15]
Additionally for arrays with unique entries such as a set of users
(using variable definitions from the question)
filtered_array = my_array - my_array.values_at(1,3)
Bonus, if your indices are inside an array themselves:
indices_to_remove = [1,3]
filtered_array = my_array - my_array.values_at(*indices_to_remove)
I think this is rather descriptive, not awkward and not shorter than needed.
One more possible solution with some addition, now it's also will work with negative indexes:
array = %w( a b c d e f )
indexes = [1, 2, -1, -9, -6, 6]
def array_except(array, *indexes)
indexes = indexes.map { |e| e.negative? ? e + array.length : e }
array.values_at(*((0...array.length).to_a - indexes))
end
array_except(array, *indexes)
=> ["d", "e"]
array_except(array, 0, -1)
=> ["b", "c", "d", "e"]

Using .map function to create hashes

I have an array [5,2,6,4] and I would like to create a structure such as the first minus the second etc until the last row.
I have tried using map, but not sure how to proceed since i might need indxes.
I would like to store the result in something that looks like:
{1 => (5, 2, 3), 2 =>(2,6,-4), 3 => (6,4,2)}
So an array of x should return x-1 hashes.
Anybody knows how to do? should be a simple one.
Thank you.
First, you want to work with the array elements in pairs: 5,2, 2,6, ... That means you want to use each_cons:
a.each_cons(2) { |(e1, e2)| ... }
Then you'll want the index to get the 1, 2, ... hash keys; that suggests throwing a Enumerator#with_index into the mix:
a.each_cons(2).with_index { |(e1, e2), i| ... }
Then you can use with_object to get the final piece (the hash) into play:
a.each_cons(2).with_index.with_object({}) { |((e1, e2), i), h| h[i + 1] = [e1, e2, e1 - e2] }
If you think all the parentheses in the block's arguments are too noisy then you can do it in steps rather than a single one-liner.
You can use each_index:
a = [5, 2, 6, 4]
h = {}
a[0..-2].each_index { |i| h[i+1] = [a[i], a[i+1], a[i] - a[i+1]] }
h
=> {1=>[5, 2, 3], 2=>[2, 6, -4], 3=>[6, 4, 2]}
Try to use
each_with_index
Suppose you have an array:
arr = [3,[2,3],4,5]
And you want to covert with hash(key-value pair). 'Key' denotes an index of an array and 'value' denotes value of an array. Take a blank hash and iterate with each_with_index and pushed into the hash and finally print the hash.
Try this:
hash={}
arr.each_with_index do |val, index|
hash[index]=val
end
p hash
Its output will be:
{0=>3, 1=>[2, 3], 2=>4, 3=>5}
If you want that index always starts with 1 or 2 etc then use
arr.each.with_index(1) do |val, index|
hash[index] = val
end
Output will be:
{1=>3, 2=>[2, 3], 3=>4, 4=>5}

Ruby:-- Accept array as input and put it into hash

User must enter the array as input. Hash has to accept the input array elements as values.
Create a Ruby program for this by using loops. If array completed print this statement “All array elements are assigned to keys in the hash”
A = [1, 6, 4, 5]
H = {“k1” => 1
“k2” => 6
“k3” => 4
“k4” => 5}
Another solution can be,
a.each_with_index.inject({}) { |m,(a,i)| m["k#{i+1}"] = a; m }
Update: answering to your question
puts 'Enter number of hash elements'
n = gets.to_i
n.times |i|
hash["k#{i+1}"] = gets.to_i
end
puts 'All array elements are assigned to keys in the hash'
A = [1, 6, 4, 5]
Hash[[*'k1'.."k#{A.length}"].zip(A)]

Intersect array of hashes with array of ids

I have an array of hashes, this is not an active record model. This array is of objects of type Person with properties of id, name, age. I have a second array of strings, ["john", "james", "bill"].
I am attempting to remove all objects in the array of hashes except for the ones who have names in the second array, essentially performing an intersect, but I'm having quite a few problems. Any suggestions? I'm not sure if my syntax is just off or if I'm thinking about this the wrong way. Obviously I can just iterate through but this seems like its probably not the best way to handle the situation.
http://www.ruby-doc.org/core-1.9.2/Array.html#method-i-select
arr1 = [{:id => 1, :name => "John"}, {:id => 2, :name => "Doe"}];
arr2 = ["Doe"];
intersect = arr1.select {|o| arr2.include? o[:name]} # you can also use select!
p intersect # outputs [{:name=>"Doe", :id=>2}]
Late to the party, but if arr1 :name is an array this works nicely:
arr1 = [{:id => 1, :name => ["John", "Doe"]}, {:id => 2, :name => ["Doe"]}];
arr2 = ["Doe"]
> intersect = arr1.reject{|o| (arr2 & o[:name]).empty?}
=> [{:id=>1, :name=>["John", "Doe"]}, {:id=>2, :name=>["Doe"]}] #output
> arr2 = ["John"]
> intersect = arr1.reject{|o| (arr2 & o[:name]).empty?}
=> [{:id=>1, :name=>["John", "Doe"]}] #output
or use select:
intersect = arr1.select{|o| !(arr2 & o[:name]).empty?}
To remove all objects in the array of hashes except for the ones who have names in the second array, you can do:
arr1.reject!{|o| (arr2 & o[:name]).empty?}

Resources