Ruby: Compare 2 Arrays for Matches, and Count the Number of Match Instances

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 aliassize):

a.select{|e| (index = b.index(e) and b.delete_at index)}.size

Demonstration

Results:

  1. a, b = [0,0,5], [0,5,5] output: => 2;
  2. a, b = [1,2,2,3], [1,2,3,4] output: => 3;
  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



Leave a reply



Submit