1

For example:

a = [1,2,3,4,5,6,7,8]  
b = [1,9,10,11,12,13,14,15]

a array has 1 and b array has 1 too. So they have the same element.

How to compare them and return true or false with ruby?

s-cho-m
  • 967
  • 2
  • 13
  • 28

3 Answers3

3

Check if a & b is empty:

a & b
# => [1]
(a & b).empty?
# => false
Yu Hao
  • 119,891
  • 44
  • 235
  • 294
0

If you have many elements per Array, doing an intersection (&) can be an expensive operation. I assume that it would be quicker to go 'by hand':

def have_same_element?(array1, array2)
  # Return true on first element found that is in both array1 and array2
  # Return false if no such element found
  array1.each do |elem|
    return true if array2.include?(elem)
  end
  return false
end

a = [*1..100] # [1, 2, 3, ... , 100]
b = a.reverse.to_a # [100, 99, 98, ... , 1]
puts have_same_element?(a, b)

If you know more beforehand (e.g. "array1 contains many duplicates") you can further optimize the operation (e.g. by calling uniq or compact first, depending on your data).

Would be interesting to see actual benchmarks.

Edit

require 'benchmark'
Benchmark.bmbm(10) do |bm|
  bm.report("by hand") {have_same_element?(a, b)}
  bm.report("set operation") { (a & b).empty? }
end

Rehearsal -------------------------------------------------
by hand         0.000000   0.000000   0.000000 (  0.000014)
set operation   0.000000   0.000000   0.000000 (  0.000095)
---------------------------------------- total: 0.000000sec

                    user     system      total        real
by hand         0.000000   0.000000   0.000000 (  0.000012)
set operation   0.000000   0.000000   0.000000 (  0.000131)

So, in this case it looks as if the "by hand" method is really faster, but its quite a sloppy method of benchmarking with limited expressiveness.

Also, see @CarySwoveland s excellent comments about using sets, proper benchmarking and a snappier expression using find (detect would do the same and be more expressive imho - but carefull as it returns the value found - if your arrays contain falsey values like nil (or false)...; you generally want to use any?{} here).

Felix
  • 4,510
  • 2
  • 31
  • 46
  • Thank you very much. Your answer is also so good. But I don't know how expensive the `&` can cost? Maybe that method cost much time than `each` and `include`. – s-cho-m Sep 08 '15 at 06:00
  • see the benchmark for the given scenario :) Like that it is easy to play through with your given data. In any case, optimizations like that do only make sense imho if you have a lot of data and performance is an issue. Otherwise choose what reads better to you. – Felix Sep 08 '15 at 06:03
  • A very good answer. Thank you very much! It is a good way to test which method is better. It seems that `&` is really expensive when the array is too big. – s-cho-m Sep 08 '15 at 06:09
  • You need to be careful with benchmarks. `by_hand` works well for your benchmark because the first elements of `a` and `b` are the same. Better to use a variety of larger randomized arrays. Also, `array2.include?(elem)`, which you do until you find a match in `array1`, is extremely inefficient, since you repeatedly traversing `array2`. Better: `require 'set'; s2 = array2.to_set; array1.find { |e| s2.include?(e) }`. Set lookups--effectively hash lookups--are extremely fast. My guess that this would be faster than set intersection in most cases. – Cary Swoveland Sep 08 '15 at 07:09
  • 1
    Try benchmarking with `a = Array.new(n) { rand m }; b = Array.new(p) { rand q } for a few combinations of `n`, `m`, `p` and `q`. – Cary Swoveland Sep 08 '15 at 07:18
  • @CarySwoveland benchmarking is always hairy, if the conditions are not known. Thats why i proposed `uniq` (probably `to_set()` is even more performant and gives the benefits you described). Also, if we know that data can be sorted, we can spend a lot of brains into getting faster. Feel free to add an Update to the answer mentioning your approach using sets (i might find the time to do it myself - i might not, and you get reputation for accepted edits :) ). Thanks a lot for your thoughts on the issue! – Felix Sep 08 '15 at 10:01
-1

Intersection of two arrays can get using & operator. If you need to get similar elements in two arrays, take intersect as

a = [1,2,3,4,5,6,7,8]  
b = [1,9,10,11,12,13,14,15]

and taking intersection

u = a & b
puts u
# [1]

u.empty?
# false
Shahzad Tariq
  • 2,767
  • 1
  • 22
  • 31
  • Utterly the same exact answer with just slight formatting changes as posted here. http://stackoverflow.com/questions/2603895/how-can-i-check-if-a-ruby-array-includes-one-of-several-values – Giacomo1968 Sep 08 '15 at 06:25
  • 2
    You've already posted [this answer](http://stackoverflow.com/a/32450709/477037), no need to duplicate it. – Stefan Sep 08 '15 at 08:01