Ruby: Compare 2 arrays for matches, and count the number of match instances
You can do this with array intersection:
@array1 = ['a', 'b', 'c', 'd', 'e']
@array2 = ['d', 'e', 'f', 'g', 'h']
@intersection = @array1 & @array2
@intersection should now be ['d', 'e']. You can then do the following:
<% if !@intersection.empty? %>
<%= @intersection.size %> Matches Found.
<% else %>
No Matches Found.
<% end %>
arrays comparison
There is already a method defined in Array class for this called '&':
ary & other_ary → new_ary
Set Intersection—Returns a new array containing elements common to the two arrays, with no duplicates.
[ 1, 1, 3, 5 ] & [ 1, 2, 3 ] #=> [ 1, 3 ]
how to match the contents of two arrays and get corresponding index ruby
If you want to find matching elements between two arrays just use &
like so:
array1 = [2,3,4,5,6,7] #does not have repeated values[2,2,3] and the values are sorted
array2 = [2,5,7]
matches = array1 & array2
=> [2, 5, 7]
To print the matches and indexes found in each array, just loop through the matches array like so:
matches.each do |number|
puts "Match found element #{number}"
puts "array1 index=#{array1.rindex(number)}"
puts "array2 index=#{array2.rindex(number)}"
end
Match found element 2
array1 index=0
array2 index=0
Match found element 5
array1 index=3
array2 index=1
Match found element 7
array1 index=5
array2 index=2
Check if two arrays have the same contents (in any order)
This doesn't require conversion to set:
a.sort == b.sort
Ruby: Compare two arrays for matches, and order results in DESC order
If you're dead set on using sort_by
then you can just negate the numbers:
def index
@users = User.all.sort_by { |el|
-(el.compare_resturants & current_user.compare_resturants).length
}
end
This trick only works because you're sorting by numeric values. If you were sorting on strings then you'd have to use something like this:
reverse_sorted = a.sort_by { |x| something(x) }.reverse
but that would involve an extra copy of the array and the extra work that reverse
would do. In such cases you should use a full sort
with reversed comparison logic.
If you're were trying to use sort_by
to avoid computing something expensive for each comparison and you were sorting on something non-numeric, then you could always use sort
with an explicit Schwartzian Transform to compute the expensive things only once.
How to count duplicates in Ruby Arrays
This will yield the duplicate elements as a hash with the number of occurences for each duplicate item. Let the code speak:
#!/usr/bin/env ruby
class Array
# monkey-patched version
def dup_hash
inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select {
|k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
end
end
# unmonkeey'd
def dup_hash(ary)
ary.inject(Hash.new(0)) { |h,e| h[e] += 1; h }.select {
|_k,v| v > 1 }.inject({}) { |r, e| r[e.first] = e.last; r }
end
p dup_hash([1, 2, "a", "a", 4, "a", 2, 1])
# {"a"=>3, 1=>2, 2=>2}
p [1, 2, "Thanks", "You're welcome", "Thanks",
"You're welcome", "Thanks", "You're welcome"].dup_hash
# {"You're welcome"=>3, "Thanks"=>3}
Counting matching elements in an array
You can accomplish it with count
:
a.count{|e| index = b.index(e) and b.delete_at index }
Demonstration
or with inject
:
a.inject(0){|count, e| count + ((index = b.index(e) and b.delete_at index) ? 1 : 0)}
Demonstration
or with select
and length
(or it's alias – size
):
a.select{|e| (index = b.index(e) and b.delete_at index)}.size
Demonstration
Results:
a, b = [0,0,5], [0,5,5]
output:=> 2
;a, b = [1,2,2,3], [1,2,3,4]
output:=> 3
;a, b = [1,0,0,3], [0,0,1,4]
output=> 3
.
Needing to find matches in my controller from an array! Ruby on Rails
I think part of the problem here is that you can make new objects with the same attributes but that do not respond properly to the comparisons that the intersection operator :& uses.
Example:
class Thing
attr_reader :first,:last
def initialize(first,last)
@first = first
@last = last
end
end
thing1 = Thing.new("John","Smith")
thing2 = Thing.new("John","Smith")
thing1 == thing2
# => false
[thing1] & [thing2]
# => []
You might consider mapping each array to some identifying value (maybe id) and finding the intersection of those arrays. That is to say
@set1 = Set1.find(params[:id])
@set2 = Set2.where(:date => @set1.date)
@array1 = [Set1.find(params[:id]).let1, Set1.find(params[:id]).let2]
@array2 = [Winnings.where(:date => @set1.date).let1, Winnings.where(:date => @set1.date).let2]
@array1.map{|obj| obj.id} & @array2.map{|obj| obj.id}
# => an array of unique object ids that are in both @array1 and @array2
Or, if you want the objects themselves...
(@array1.map{|obj| obj.id} & @array2.map{|obj| obj.id}).map{ |id| Set.find(id) }
Ruby count # of matches in string from array
['test', 'is'].count{ |s| /\b#{s}\b/ =~ 'This is a test string' }
Edit: adjusted for full word matching.
Related Topics
How to Use Correct Ruby in Vim? How to Modify $Path in Vim
Dynamically Creating a Multi-Dimensional Hash in Ruby
How to Sort in Ruby/Rails on Two Fields
How to Merge Two Hashes with No New Keys
Emacs Ruby-Mode Indentation Behavior
Ruby Koan: Constants Become Symbols
How to Backreference in Ruby Regular Expression (Regex) with Gsub When I Use Grouping
How to Get My MAChine's Ip Address from Ruby Without Leveraging from Other Ip Address
How to Reverse Ruby's Include Function
How to Add a Virtual Attribute to a Model in Ruby on Rails
Any Way to Determine Which Object Called a Method
How to Install an Older Version of Jekyll
Maintaining Cookies Between Mechanize Requests
How to Include Video in Jekyll Markdown Blog
How to Use the Rails Helper "Distance_Of_Time_In_Words" in Plain Old Ruby (Non-Rails)
How to Execute Ruby Template Files (Erb) Without a Web Server from Command Line